diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.1.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.1	2018-02-23 12:47:54.075972154 -0500
@@ -1,4 +1,4 @@
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/cfftot1.cc	2018-02-23 12:47:54.075972154 -0500
@@ -1,6 +1,6 @@
 /* cfftot1.cc -- driver for translating CFF fonts to Type 1 fonts
  *
- * Copyright (c) 2002-2016 Eddie Kohler
+ * Copyright (c) 2002-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -221,7 +221,7 @@ main(int argc, char *argv[])
 
 	  case VERSION_OPT:
 	    printf("cfftot1 (LCDF typetools) %s\n", VERSION);
-	    printf("Copyright (C) 2002-2016 Eddie Kohler\n\
+	    printf("Copyright (C) 2002-2018 Eddie Kohler\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");
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/maket1font.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/maket1font.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/maket1font.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/cfftot1/maket1font.cc	2018-02-23 12:47:54.076972128 -0500
@@ -1,6 +1,6 @@
 /* maket1font.{cc,hh} -- translate CFF fonts to Type 1 fonts
  *
- * Copyright (c) 2002-2016 Eddie Kohler
+ * Copyright (c) 2002-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/configure.ac.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/configure.ac
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/configure.ac.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/configure.ac	2018-02-23 12:47:54.076972128 -0500
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT([lcdf-typetools], [2.106])
+AC_INIT([lcdf-typetools], [2.107])
 AC_CONFIG_SRCDIR([NEWS.md])
 AM_INIT_AUTOMAKE
 AC_CONFIG_HEADERS([autoconf.h])
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/config.h.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/config.h
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/config.h.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/config.h	2018-02-23 12:47:54.076972128 -0500
@@ -7,7 +7,6 @@
 #ifdef WIN32
 # ifdef __MINGW32__
 #  include <winsock2.h>
-#  include <windows.h>
 # else
 #  include <win32lib.h>
 # endif
@@ -39,6 +38,11 @@ double good_strtod(const char *s, char *
 }
 /* Get rid of a possible inline macro under C++. */
 # define inline inline
+
+/* Ignore `noexcept` if compiler is too old. */
+#if __cplusplus < 201103L
+#define noexcept
+#endif
 #endif
 
 #endif /* LCDF_TYPETOOLS_CONFIG_H */
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/cff.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/cff.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/cff.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/cff.hh	2018-02-23 12:47:54.076972128 -0500
@@ -31,7 +31,7 @@ class Cff { public:
 
     int nfonts() const                  { return _name_index.size(); }
     PermString font_name(int i) const   { return _name_index[i]; }
-    FontParent *font(PermString = PermString(), ErrorHandler * = 0);
+    FontParent* font(PermString = PermString(), ErrorHandler* = 0);
 
     enum { NSTANDARD_STRINGS = 391, MAX_SID = 64999 };
     int max_sid() const                 { return NSTANDARD_STRINGS - 1 + _strings.size(); }
@@ -125,13 +125,12 @@ class Cff { public:
     mutable HashMap<PermString, int> _strings_map;
 
     IndexIterator _gsubrs_index;
-    Vector<Charstring *> _gsubrs_cs;
+    Vector<Charstring*> _gsubrs_cs;
+    Vector<FontParent*> _fonts;
 
     unsigned _units_per_em;
 
     int parse_header(ErrorHandler *);
-    int font_offset(int, int &, int &) const;
-    int font_offset(PermString, int &, int &) const;
 
     enum { HEADER_SIZE = 4 };
 
@@ -238,12 +237,14 @@ class Cff::FontParent : public Charstrin
     Cff* _cff;
     int _charstring_type;
     int _error;
+    int _font_index;
 
     FontParent(const FontParent &);
     FontParent &operator=(const FontParent &);
 
     Charstring *charstring(const IndexIterator &, int) const;
 
+    friend class Cff;
     friend class Cff::Font;
     friend class Cff::CIDFont;
     friend class Cff::ChildFont;
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfdata.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfdata.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfdata.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfdata.hh	2018-02-23 12:47:54.077972103 -0500
@@ -83,20 +83,20 @@ class Data {
     static inline int32_t s32_aligned16(const unsigned char* s);
     static inline int32_t s32_aligned(const unsigned char* s);
 
-    inline uint8_t operator[](unsigned offset) const throw (Bounds);
-    inline uint16_t u16(unsigned offset) const throw (Bounds);
-    inline int16_t s16(unsigned offset) const throw (Bounds);
-    inline uint32_t u32(unsigned offset) const throw (Bounds);
-    inline int32_t s32(unsigned offset) const throw (Bounds);
-    inline uint8_t operator[](int offset) const throw (Bounds);
-    inline uint16_t u16(int offset) const throw (Bounds);
-    inline int16_t s16(int offset) const throw (Bounds);
-    inline uint32_t u32(int offset) const throw (Bounds);
-    inline int32_t s32(int offset) const throw (Bounds);
-
-    Data subtable(unsigned offset) const throw (Bounds);
-    Data offset_subtable(unsigned offset_offset) const throw (Bounds);
-    inline Data substring(int left, int len = -1) const throw ();
+    inline uint8_t operator[](unsigned offset) const;
+    inline uint16_t u16(unsigned offset) const;
+    inline int16_t s16(unsigned offset) const;
+    inline uint32_t u32(unsigned offset) const;
+    inline int32_t s32(unsigned offset) const;
+    inline uint8_t operator[](int offset) const;
+    inline uint16_t u16(int offset) const;
+    inline int16_t s16(int offset) const;
+    inline uint32_t u32(int offset) const;
+    inline int32_t s32(int offset) const;
+
+    Data subtable(unsigned offset) const;
+    Data offset_subtable(unsigned offset_offset) const;
+    inline Data substring(int left, int len = -1) const noexcept;
 
     void align_long()                   { _str.align(4); }
 
@@ -106,7 +106,7 @@ class Data {
 
 };
 
-inline uint8_t Data::operator[](unsigned offset) const throw (Bounds) {
+inline uint8_t Data::operator[](unsigned offset) const {
     if (offset >= static_cast<unsigned>(_str.length()))
         throw Bounds();
     else
@@ -114,11 +114,7 @@ inline uint8_t Data::operator[](unsigned
 }
 
 inline uint16_t Data::u16(const unsigned char* s) {
-#if __x86__ || __x86_64__ || HAVE_INDIFFERENT_ALIGNMENT
-    return ntohs(*reinterpret_cast<const uint16_t*>(s));
-#else
     return (s[0] << 8) + s[1];
-#endif
 }
 
 inline uint16_t Data::u16_aligned(const unsigned char* s) {
@@ -127,11 +123,7 @@ inline uint16_t Data::u16_aligned(const
 }
 
 inline int16_t Data::s16(const unsigned char* s) {
-#if __x86__ || __x86_64__ || HAVE_INDIFFERENT_ALIGNMENT
-    return ntohs(*reinterpret_cast<const int16_t*>(s));
-#else
     return (int16_t) ((s[0] << 8) + s[1]);
-#endif
 }
 
 inline int16_t Data::s16_aligned(const unsigned char* s) {
@@ -140,20 +132,12 @@ inline int16_t Data::s16_aligned(const u
 }
 
 inline uint32_t Data::u32(const unsigned char* s) {
-#if __x86__ || __x86_64__ || HAVE_INDIFFERENT_ALIGNMENT
-    return ntohl(*reinterpret_cast<const uint32_t*>(s));
-#else
-    return (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
-#endif
+    return ((unsigned) s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
 }
 
 inline uint32_t Data::u32_aligned16(const unsigned char* s) {
-#if __x86__ || __x86_64__ || HAVE_INDIFFERENT_ALIGNMENT
-    return ntohl(*reinterpret_cast<const uint32_t*>(s));
-#else
     efont_precondition((reinterpret_cast<uintptr_t>(s) & 1) == 0);
-    return (u16_aligned(s) << 16) + u16_aligned(s + 2);
-#endif
+    return ((unsigned) u16_aligned(s) << 16) + u16_aligned(s + 2);
 }
 
 inline uint32_t Data::u32_aligned(const unsigned char* s) {
@@ -162,20 +146,12 @@ inline uint32_t Data::u32_aligned(const
 }
 
 inline int32_t Data::s32(const unsigned char* s) {
-#if __x86__ || __x86_64__ || HAVE_INDIFFERENT_ALIGNMENT
-    return ntohl(*reinterpret_cast<const int32_t*>(s));
-#else
-    return (int32_t) ((s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]);
-#endif
+    return (int32_t) (((unsigned) s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]);
 }
 
 inline int32_t Data::s32_aligned16(const unsigned char* s) {
-#if __x86__ || __x86_64__ || HAVE_INDIFFERENT_ALIGNMENT
-    return ntohl(*reinterpret_cast<const int32_t*>(s));
-#else
     efont_precondition((reinterpret_cast<uintptr_t>(s) & 1) == 0);
-    return (int32_t) ((u16_aligned(s) << 16) + u16_aligned(s + 2));
-#endif
+    return (int32_t) (((unsigned) u16_aligned(s) << 16) + u16_aligned(s + 2));
 }
 
 inline int32_t Data::s32_aligned(const unsigned char* s) {
@@ -183,55 +159,55 @@ inline int32_t Data::s32_aligned(const u
     return ntohl(*reinterpret_cast<const int32_t*>(s));
 }
 
-inline uint16_t Data::u16(unsigned offset) const throw (Bounds) {
+inline uint16_t Data::u16(unsigned offset) const {
     if (offset + 1 >= static_cast<unsigned>(_str.length()) || offset + 1 == 0)
         throw Bounds();
     else
         return u16_aligned(_str.udata() + offset);
 }
 
-inline int16_t Data::s16(unsigned offset) const throw (Bounds) {
+inline int16_t Data::s16(unsigned offset) const {
     if (offset + 1 >= static_cast<unsigned>(_str.length()) || offset + 1 == 0)
         throw Bounds();
     else
         return s16_aligned(_str.udata() + offset);
 }
 
-inline uint32_t Data::u32(unsigned offset) const throw (Bounds) {
+inline uint32_t Data::u32(unsigned offset) const {
     if (offset + 3 >= static_cast<unsigned>(_str.length()) || offset + 3 < 3)
         throw Bounds();
     else
         return u32_aligned16(_str.udata() + offset);
 }
 
-inline int32_t Data::s32(unsigned offset) const throw (Bounds) {
+inline int32_t Data::s32(unsigned offset) const {
     if (offset + 3 >= static_cast<unsigned>(_str.length()) || offset + 3 < 3)
         throw Bounds();
     else
         return s32_aligned16(_str.udata() + offset);
 }
 
-inline uint8_t Data::operator[](int offset) const throw (Bounds) {
+inline uint8_t Data::operator[](int offset) const {
     return (*this)[unsigned(offset)];
 }
 
-inline uint16_t Data::u16(int offset) const throw (Bounds) {
+inline uint16_t Data::u16(int offset) const {
     return u16(unsigned(offset));
 }
 
-inline int16_t Data::s16(int offset) const throw (Bounds) {
+inline int16_t Data::s16(int offset) const {
     return s16(unsigned(offset));
 }
 
-inline uint32_t Data::u32(int offset) const throw (Bounds) {
+inline uint32_t Data::u32(int offset) const {
     return u32(unsigned(offset));
 }
 
-inline int32_t Data::s32(int offset) const throw (Bounds) {
+inline int32_t Data::s32(int offset) const {
     return s32(unsigned(offset));
 }
 
-inline Data Data::substring(int left, int len) const throw () {
+inline Data Data::substring(int left, int len) const noexcept {
     return Data(_str.substring(left, len));
 }
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgpos.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgpos.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgpos.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgpos.hh	2018-02-23 12:47:54.077972103 -0500
@@ -9,7 +9,7 @@ class Positioning;
 
 class Gpos { public:
 
-    Gpos(const Data &, ErrorHandler * = 0) throw (Error);
+    Gpos(const Data &, ErrorHandler * = 0);
     // default destructor
 
     const ScriptList &script_list() const { return _script_list; }
@@ -29,7 +29,7 @@ class Gpos { public:
 };
 
 class GposLookup { public:
-    GposLookup(const Data &) throw (Error);
+    GposLookup(const Data &);
     int type() const                    { return _type; }
     uint16_t flags() const              { return _d.u16(2); }
     bool unparse_automatics(Vector<Positioning> &, ErrorHandler * = 0) const;
@@ -66,9 +66,9 @@ class GposValue { public:
 };
 
 class GposSingle { public:
-    GposSingle(const Data &) throw (Error);
+    GposSingle(const Data &);
     // default destructor
-    Coverage coverage() const throw ();
+    Coverage coverage() const noexcept;
     void unparse(Vector<Positioning> &) const;
     enum { F2_HEADERSIZE = 8 };
   private:
@@ -76,9 +76,9 @@ class GposSingle { public:
 };
 
 class GposPair { public:
-    GposPair(const Data &) throw (Error);
+    GposPair(const Data &);
     // default destructor
-    Coverage coverage() const throw ();
+    Coverage coverage() const noexcept;
     void unparse(Vector<Positioning> &) const;
     enum { F1_HEADERSIZE = 10, F1_RECSIZE = 2,
            PAIRSET_HEADERSIZE = 2, PAIRVALUE_HEADERSIZE = 2,
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgsub.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgsub.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgsub.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfgsub.hh	2018-02-23 12:47:54.077972103 -0500
@@ -9,7 +9,7 @@ class Substitution;
 
 class Gsub { public:
 
-    Gsub(const Data &, const Font *, ErrorHandler * = 0) throw (Error);
+    Gsub(const Data &, const Font *, ErrorHandler * = 0);
     // default destructor
 
     const ScriptList &script_list() const { return _script_list; }
@@ -31,7 +31,7 @@ class Gsub { public:
 };
 
 class GsubLookup { public:
-    GsubLookup(const Data &) throw (Error);
+    GsubLookup(const Data &);
     int type() const                    { return _type; }
     uint16_t flags() const              { return _d.u16(2); }
     void mark_out_glyphs(const Gsub &gsub, Vector<bool> &gmap) const;
@@ -49,9 +49,9 @@ class GsubLookup { public:
 };
 
 class GsubSingle { public:
-    GsubSingle(const Data &) throw (Error);
+    GsubSingle(const Data &);
     // default destructor
-    Coverage coverage() const throw ();
+    Coverage coverage() const noexcept;
     Glyph map(Glyph) const;
     void mark_out_glyphs(Vector<bool> &gmap) const;
     void unparse(Vector<Substitution> &subs, const Coverage &limit) const;
@@ -62,9 +62,9 @@ class GsubSingle { public:
 };
 
 class GsubMultiple { public:
-    GsubMultiple(const Data &) throw (Error);
+    GsubMultiple(const Data &);
     // default destructor
-    Coverage coverage() const throw ();
+    Coverage coverage() const noexcept;
     bool map(Glyph, Vector<Glyph> &) const;
     void mark_out_glyphs(Vector<bool> &gmap) const;
     void unparse(Vector<Substitution> &, bool alternate = false) const;
@@ -76,9 +76,9 @@ class GsubMultiple { public:
 };
 
 class GsubLigature { public:
-    GsubLigature(const Data &) throw (Error);
+    GsubLigature(const Data &);
     // default destructor
-    Coverage coverage() const throw ();
+    Coverage coverage() const noexcept;
     bool map(const Vector<Glyph> &, Glyph &, int &) const;
     void mark_out_glyphs(Vector<bool> &gmap) const;
     void unparse(Vector<Substitution> &) const;
@@ -91,9 +91,9 @@ class GsubLigature { public:
 };
 
 class GsubContext { public:
-    GsubContext(const Data &) throw (Error);
+    GsubContext(const Data &);
     // default destructor
-    Coverage coverage() const throw ();
+    Coverage coverage() const noexcept;
     void mark_out_glyphs(const Gsub &gsub, Vector<bool> &gmap) const;
     bool unparse(const Gsub &gsub, Vector<Substitution> &out_subs, const Coverage &limit) const;
     enum { F3_HSIZE = 6, SUBRECSIZE = 4 };
@@ -113,9 +113,9 @@ class GsubContext { public:
 };
 
 class GsubChainContext { public:
-    GsubChainContext(const Data &) throw (Error);
+    GsubChainContext(const Data &);
     // default destructor
-    Coverage coverage() const throw ();
+    Coverage coverage() const noexcept;
     void mark_out_glyphs(const Gsub &gsub, Vector<bool> &gmap) const;
     bool unparse(const Gsub &gsub, Vector<Substitution> &subs, const Coverage &limit) const;
     enum { F1_HEADERSIZE = 6, F1_RECSIZE = 2,
@@ -199,7 +199,7 @@ class Substitution { public:
     void add_outer_left(Glyph);
     void remove_outer_left();
     Substitution in_out_append_glyph(Glyph) const;
-    bool out_alter(const Substitution &, int) throw ();
+    bool out_alter(const Substitution &, int) noexcept;
     void add_outer_right(Glyph);
     void remove_outer_right();
 
@@ -238,14 +238,14 @@ class Substitution { public:
     static bool substitute_in(const Substitute &, uint8_t, const Coverage &);
     static bool substitute_in(const Substitute &, uint8_t, const GlyphSet &);
 
-    static Glyph extract_glyph(const Substitute &, uint8_t) throw ();
-    static Glyph extract_glyph(const Substitute &, int which, uint8_t) throw ();
-    static bool extract_glyphs(const Substitute &, uint8_t, Vector<Glyph> &, bool coverage_ok) throw ();
-    static Glyph *extract_glyphptr(const Substitute &, uint8_t) throw ();
-    static int extract_nglyphs(const Substitute &, uint8_t, bool coverage_ok) throw ();
-    static bool matches(const Substitute &, uint8_t, int pos, Glyph) throw ();
+    static Glyph extract_glyph(const Substitute &, uint8_t) noexcept;
+    static Glyph extract_glyph(const Substitute &, int which, uint8_t) noexcept;
+    static bool extract_glyphs(const Substitute &, uint8_t, Vector<Glyph> &, bool coverage_ok) noexcept;
+    static Glyph *extract_glyphptr(const Substitute &, uint8_t) noexcept;
+    static int extract_nglyphs(const Substitute &, uint8_t, bool coverage_ok) noexcept;
+    static bool matches(const Substitute &, uint8_t, int pos, Glyph) noexcept;
 
-    static void unparse_glyphids(StringAccum &, const Substitute &, uint8_t, const Vector<PermString> *) throw ();
+    static void unparse_glyphids(StringAccum &, const Substitute &, uint8_t, const Vector<PermString> *) noexcept;
 
 };
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otf.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otf.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otf.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otf.hh	2018-02-23 12:47:54.077972103 -0500
@@ -142,23 +142,23 @@ class FeatureList {
 
 class Coverage {
   public:
-    Coverage() throw ();                // empty coverage
-    Coverage(Glyph first, Glyph last) throw (); // range coverage
-    Coverage(const Vector<bool> &gmap) throw (); // used-bytemap coverage
-    Coverage(const String &str, ErrorHandler *errh = 0, bool check = true) throw ();
+    Coverage() noexcept;                // empty coverage
+    Coverage(Glyph first, Glyph last) noexcept; // range coverage
+    Coverage(const Vector<bool> &gmap) noexcept; // used-bytemap coverage
+    Coverage(const String &str, ErrorHandler *errh = 0, bool check = true) noexcept;
     // default destructor
 
-    bool ok() const throw ()            { return _str.length() > 0; }
-    int size() const throw ();
-    bool has_fast_covers() const throw () {
+    bool ok() const noexcept            { return _str.length() > 0; }
+    int size() const noexcept;
+    bool has_fast_covers() const noexcept {
         return _str.length() > 0 && _str.data()[1] == T_X_BYTEMAP;
     }
 
-    int coverage_index(Glyph) const throw ();
-    bool covers(Glyph g) const throw () { return coverage_index(g) >= 0; }
+    int coverage_index(Glyph) const noexcept;
+    bool covers(Glyph g) const noexcept { return coverage_index(g) >= 0; }
 
-    void unparse(StringAccum&) const throw ();
-    String unparse() const throw ();
+    void unparse(StringAccum&) const noexcept;
+    String unparse() const noexcept;
 
     class iterator { public:
         iterator()                      : _pos(0), _value(0) { }
@@ -194,7 +194,7 @@ class Coverage {
 
     iterator begin() const              { return iterator(_str, false); }
     iterator end() const                { return iterator(_str, true); }
-    Glyph operator[](int) const throw ();
+    Glyph operator[](int) const noexcept;
 
     enum { T_LIST = 1, T_RANGES = 2, T_X_BYTEMAP = 3,
            HEADERSIZE = 4, LIST_RECSIZE = 2, RANGES_RECSIZE = 6 };
@@ -238,17 +238,17 @@ class GlyphSet {
 
 class ClassDef {
   public:
-    ClassDef(const String&, ErrorHandler* = 0) throw ();
+    ClassDef(const String&, ErrorHandler* = 0) noexcept;
     // default destructor
 
     bool ok() const                     { return _str.length() > 0; }
-    int nclass() const throw ();
+    int nclass() const noexcept;
 
-    int lookup(Glyph) const throw ();
-    int operator[](Glyph g) const throw () { return lookup(g); }
+    int lookup(Glyph) const noexcept;
+    int operator[](Glyph g) const noexcept { return lookup(g); }
 
-    void unparse(StringAccum&) const throw ();
-    String unparse() const throw ();
+    void unparse(StringAccum&) const noexcept;
+    String unparse() const noexcept;
 
     class class_iterator {
       public:
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfos2.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfos2.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfos2.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/otfos2.hh	2018-02-23 12:47:54.077972103 -0500
@@ -25,15 +25,15 @@ class Os2 { public:
                    O_LOWEROPTICALPOINTSIZE = 96, O_UPPEROPTICALPOINTSIZE = 98 };
     enum { HEADER_SIZE = 2 };
 
-    inline int16_t typo_ascender() const throw (Bounds);
-    inline int16_t typo_descender() const throw (Bounds);
-    inline int16_t typo_line_gap() const throw (Bounds);
-    inline int16_t x_height() const throw (Bounds);
-    inline int16_t cap_height() const throw (Bounds);
-    inline double lower_optical_point_size() const throw (Bounds);
-    inline double upper_optical_point_size() const throw (Bounds);
-    inline bool has_optical_point_size() const throw ();
-    inline String vendor_id() const throw ();
+    inline int16_t typo_ascender() const;
+    inline int16_t typo_descender() const;
+    inline int16_t typo_line_gap() const;
+    inline int16_t x_height() const;
+    inline int16_t cap_height() const;
+    inline double lower_optical_point_size() const;
+    inline double upper_optical_point_size() const;
+    inline bool has_optical_point_size() const noexcept;
+    inline String vendor_id() const noexcept;
 
   private:
 
@@ -45,47 +45,47 @@ class Os2 { public:
 };
 
 
-inline int16_t Os2::typo_ascender() const throw (Bounds)
+inline int16_t Os2::typo_ascender() const
 {
     return _data.s16(O_TYPOASCENDER);
 }
 
-inline int16_t Os2::typo_descender() const throw (Bounds)
+inline int16_t Os2::typo_descender() const
 {
     return _data.s16(O_TYPODESCENDER);
 }
 
-inline int16_t Os2::typo_line_gap() const throw (Bounds)
+inline int16_t Os2::typo_line_gap() const
 {
     return _data.s16(O_TYPOLINEGAP);
 }
 
-inline int16_t Os2::x_height() const throw (Bounds)
+inline int16_t Os2::x_height() const
 {
     return _data.s16(O_XHEIGHT);
 }
 
-inline int16_t Os2::cap_height() const throw (Bounds)
+inline int16_t Os2::cap_height() const
 {
     return _data.s16(O_CAPHEIGHT);
 }
 
-inline double Os2::lower_optical_point_size() const throw (Bounds)
+inline double Os2::lower_optical_point_size() const
 {
     return _data.u16(O_LOWEROPTICALPOINTSIZE) / 20.;
 }
 
-inline double Os2::upper_optical_point_size() const throw (Bounds)
+inline double Os2::upper_optical_point_size() const
 {
     return _data.u16(O_UPPEROPTICALPOINTSIZE) / 20.;
 }
 
-inline bool Os2::has_optical_point_size() const throw ()
+inline bool Os2::has_optical_point_size() const noexcept
 {
     return _data.length() >= O_UPPEROPTICALPOINTSIZE + 2;
 }
 
-inline String Os2::vendor_id() const throw ()
+inline String Os2::vendor_id() const noexcept
 {
     return _data.substring(O_VENDORID, 4).string();
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/t1bounds.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/t1bounds.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/t1bounds.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/t1bounds.hh	2018-02-23 12:47:54.077972103 -0500
@@ -31,8 +31,9 @@ class CharstringBounds : public Charstri
     bool char_bounds(const CharstringContext&, bool shift = true);
     void translate(double dx, double dy);
     inline Point transform(const Point& p) const;
-    bool output(double bb[4], double& width, bool use_cur_width = false) const;
 
+    // output: [left, bottom, right, top]
+    bool output(double bb[4], double& width, bool use_cur_width = false) const;
     static bool bounds(const CharstringContext&,
                        double bounds[4], double& width);
     static bool bounds(const Transform&, const CharstringContext&,
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/ttfkern.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/ttfkern.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/ttfkern.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/efont/ttfkern.hh	2018-02-23 12:47:54.078972078 -0500
@@ -6,7 +6,7 @@ namespace Efont { namespace OpenType {
 
 class KernTable { public:
 
-    KernTable(const Data &, ErrorHandler * = 0) throw (Error);
+    KernTable(const Data &, ErrorHandler * = 0);
     // default destructor
 
     bool ok() const                     { return _error >= 0; }
@@ -34,7 +34,7 @@ class KernTable { public:
     inline uint32_t first_offset() const {
         return _version == 0 ? 4 : 8;
     }
-    inline Data subtable(uint32_t &off) const throw (Error);
+    inline Data subtable(uint32_t &off) const;
 
 };
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/bezier.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/bezier.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/bezier.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/bezier.hh	2018-02-23 12:47:54.078972078 -0500
@@ -8,30 +8,30 @@
 class Bezier { public:
 
     Bezier()				: _bb(-1) { }
-    inline Bezier(Point p[4]) throw ();
-    inline Bezier(const Point &, const Point &, const Point &, const Point &) throw ();
+    inline Bezier(Point p[4]) noexcept;
+    inline Bezier(const Point &, const Point &, const Point &, const Point &) noexcept;
 
     const Point *points() const		{ return _p; }
     const Point &point(int i) const	{ assert(i>=0&&i<4); return _p[i]; }
     Point &mpoint(int i)		{ assert(i>=0&&i<4); _bb = -1; return _p[i]; }
     void set_point(int i, const Point &p) { mpoint(i) = p; }
 
-    Point eval(double) const throw ();
-    bool is_flat(double) const throw ();
-    bool in_bb(const Point &, double) const throw ();
-    bool hit(const Point &, double) const throw ();
-
-    inline double bb_left() const throw ();
-    inline double bb_right() const throw ();
-    inline double bb_top() const throw ();
-    inline double bb_bottom() const throw ();
-
-    inline double bb_left_x() const throw ();
-    inline double bb_right_x() const throw ();
-    inline double bb_top_x() const throw ();
-    inline double bb_bottom_x() const throw ();
+    Point eval(double) const noexcept;
+    bool is_flat(double) const noexcept;
+    bool in_bb(const Point &, double) const noexcept;
+    bool hit(const Point &, double) const noexcept;
+
+    inline double bb_left() const noexcept;
+    inline double bb_right() const noexcept;
+    inline double bb_top() const noexcept;
+    inline double bb_bottom() const noexcept;
+
+    inline double bb_left_x() const noexcept;
+    inline double bb_right_x() const noexcept;
+    inline double bb_top_x() const noexcept;
+    inline double bb_bottom_x() const noexcept;
 
-    void halve(Bezier &, Bezier &) const throw ();
+    void halve(Bezier &, Bezier &) const noexcept;
 
     inline void segmentize(Vector<Point> &) const;
     void segmentize(Vector<Point> &, bool) const;
@@ -43,23 +43,23 @@ class Bezier { public:
     Point _p[4];
     mutable int _bb;
 
-    void make_bb() const throw ();
-    inline void ensure_bb() const throw ();
+    void make_bb() const noexcept;
+    inline void ensure_bb() const noexcept;
 
-    double hit_recurse(const Point &, double, double, double, double, double) const throw ();
+    double hit_recurse(const Point &, double, double, double, double, double) const noexcept;
 
 };
 
 
 inline
-Bezier::Bezier(Point p[4]) throw ()
+Bezier::Bezier(Point p[4]) noexcept
     : _bb(-1)
 {
     memcpy(_p, p, sizeof(Point) * 4);
 }
 
 inline
-Bezier::Bezier(const Point &p0, const Point &p1, const Point &p2, const Point &p3) throw ()
+Bezier::Bezier(const Point &p0, const Point &p1, const Point &p2, const Point &p3) noexcept
 {
     _p[0] = p0;
     _p[1] = p1;
@@ -69,59 +69,59 @@ Bezier::Bezier(const Point &p0, const Po
 }
 
 inline void
-Bezier::ensure_bb() const throw ()
+Bezier::ensure_bb() const noexcept
 {
     if (_bb < 0)
 	make_bb();
 }
 
 inline double
-Bezier::bb_top_x() const throw ()
+Bezier::bb_top_x() const noexcept
 {
     return _p[(_bb >> 4) & 3].y;
 }
 
 inline double
-Bezier::bb_left_x() const throw ()
+Bezier::bb_left_x() const noexcept
 {
     return _p[(_bb >> 2) & 3].x;
 }
 
 inline double
-Bezier::bb_bottom_x() const throw ()
+Bezier::bb_bottom_x() const noexcept
 {
     return _p[(_bb >> 6) & 3].y;
 }
 
 inline double
-Bezier::bb_right_x() const throw ()
+Bezier::bb_right_x() const noexcept
 {
     return _p[(_bb >> 0) & 3].x;
 }
 
 inline double
-Bezier::bb_top() const throw ()
+Bezier::bb_top() const noexcept
 {
     ensure_bb();
     return bb_top_x();
 }
 
 inline double
-Bezier::bb_left() const throw ()
+Bezier::bb_left() const noexcept
 {
     ensure_bb();
     return bb_left_x();
 }
 
 inline double
-Bezier::bb_bottom() const throw ()
+Bezier::bb_bottom() const noexcept
 {
     ensure_bb();
     return bb_bottom_x();
 }
 
 inline double
-Bezier::bb_right() const throw ()
+Bezier::bb_right() const noexcept
 {
     ensure_bb();
     return bb_right_x();
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/clp.h.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/clp.h
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/clp.h.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/clp.h	2018-02-23 12:47:54.078972078 -0500
@@ -8,7 +8,7 @@ extern "C" {
 /* clp.h - Public interface to CLP.
  * This file is part of CLP, the command line parser package.
  *
- * Copyright (c) 1997-2016 Eddie Kohler, ekohler@gmail.com
+ * Copyright (c) 1997-2018 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"),
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/point.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/point.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/point.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/point.hh	2018-02-23 12:47:54.078972078 -0500
@@ -14,28 +14,28 @@ struct Point {
     Point(const Point &p, double dx, double dy) : x(p.x + dx), y(p.y + dy) { }
     // ~Point()				use compiler default
 
-    inline double squared_length() const throw ();
-    inline double length() const throw ();
-    inline double magnitude() const throw ();
-    static inline double distance(const Point &, const Point &) throw ();
-    static inline double dot(const Point &, const Point &) throw ();
-    static Point midpoint(const Point &, const Point &) throw ();
+    inline double squared_length() const noexcept;
+    inline double length() const noexcept;
+    inline double magnitude() const noexcept;
+    static inline double distance(const Point &, const Point &) noexcept;
+    static inline double dot(const Point &, const Point &) noexcept;
+    static Point midpoint(const Point &, const Point &) noexcept;
 
-    inline double angle() const throw ();
+    inline double angle() const noexcept;
 
     void shift(double dx, double dy)	{ x += dx; y += dy; }
 
-    inline Point shifted(double dx, double dy) const throw ();
-    Point rotated(double) const throw ();
-    inline Point normal() const throw ();
-
-    bool on_line(const Point &, const Point &, double) const throw ();
-    bool on_segment(const Point &, const Point &, double) const throw ();
-
-    inline Point &operator+=(const Point &) throw ();
-    inline Point &operator-=(const Point &) throw ();
-    inline Point &operator*=(double) throw ();
-    inline Point &operator/=(double) throw ();
+    inline Point shifted(double dx, double dy) const noexcept;
+    Point rotated(double) const noexcept;
+    inline Point normal() const noexcept;
+
+    bool on_line(const Point &, const Point &, double) const noexcept;
+    bool on_segment(const Point &, const Point &, double) const noexcept;
+
+    inline Point &operator+=(const Point &) noexcept;
+    inline Point &operator-=(const Point &) noexcept;
+    inline Point &operator*=(double) noexcept;
+    inline Point &operator/=(double) noexcept;
 
     // Point operator+(Point, const Point &);
     // Point operator-(Point, const Point &);
@@ -49,44 +49,44 @@ struct Point {
 };
 
 inline double
-Point::squared_length() const throw ()
+Point::squared_length() const noexcept
 {
     return x*x + y*y;
 }
 
 inline double
-Point::length() const throw ()
+Point::length() const noexcept
 {
     return sqrt(x*x + y*y);
 }
 
 inline double
-Point::magnitude() const throw ()
+Point::magnitude() const noexcept
 {
     return length();
 }
 
 inline double
-Point::angle() const throw ()
+Point::angle() const noexcept
 {
     return atan2(y, x);
 }
 
 inline Point
-Point::shifted(double dx, double dy) const throw ()
+Point::shifted(double dx, double dy) const noexcept
 {
     return Point(x + dx, y + dy);
 }
 
 inline Point
-Point::normal() const throw ()
+Point::normal() const noexcept
 {
     double l = length();
     return (l ? Point(x/l, y/l) : *this);
 }
 
 inline Point &
-Point::operator+=(const Point &p) throw ()
+Point::operator+=(const Point &p) noexcept
 {
     x += p.x;
     y += p.y;
@@ -94,7 +94,7 @@ Point::operator+=(const Point &p) throw
 }
 
 inline Point &
-Point::operator-=(const Point &p) throw ()
+Point::operator-=(const Point &p) noexcept
 {
     x -= p.x;
     y -= p.y;
@@ -102,7 +102,7 @@ Point::operator-=(const Point &p) throw
 }
 
 inline Point &
-Point::operator*=(double d) throw ()
+Point::operator*=(double d) noexcept
 {
     x *= d;
     y *= d;
@@ -110,7 +110,7 @@ Point::operator*=(double d) throw ()
 }
 
 inline Point &
-Point::operator/=(double d) throw ()
+Point::operator/=(double d) noexcept
 {
     x /= d;
     y /= d;
@@ -118,66 +118,66 @@ Point::operator/=(double d) throw ()
 }
 
 inline bool
-operator==(const Point &a, const Point &b) throw ()
+operator==(const Point &a, const Point &b) noexcept
 {
     return a.x == b.x && a.y == b.y;
 }
 
 inline bool
-operator!=(const Point &a, const Point &b) throw ()
+operator!=(const Point &a, const Point &b) noexcept
 {
     return a.x != b.x || a.y != b.y;
 }
 
 inline Point
-operator+(Point a, const Point &b) throw ()
+operator+(Point a, const Point &b) noexcept
 {
     a += b;
     return a;
 }
 
 inline Point
-operator-(Point a, const Point &b) throw ()
+operator-(Point a, const Point &b) noexcept
 {
     a -= b;
     return a;
 }
 
 inline Point
-operator-(const Point &a) throw ()
+operator-(const Point &a) noexcept
 {
     return Point(-a.x, -a.y);
 }
 
 inline Point
-operator*(Point a, double scale) throw ()
+operator*(Point a, double scale) noexcept
 {
     a *= scale;
     return a;
 }
 
 inline Point
-operator*(double scale, Point a) throw ()
+operator*(double scale, Point a) noexcept
 {
     a *= scale;
     return a;
 }
 
 inline Point
-operator/(Point a, double scale) throw ()
+operator/(Point a, double scale) noexcept
 {
     a /= scale;
     return a;
 }
 
 inline double
-Point::distance(const Point &a, const Point &b) throw ()
+Point::distance(const Point &a, const Point &b) noexcept
 {
     return (a - b).length();
 }
 
 inline double
-Point::dot(const Point &a, const Point &b) throw ()
+Point::dot(const Point &a, const Point &b) noexcept
 {
     return a.x*b.x + a.y*b.y;
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/straccum.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/straccum.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/straccum.hh.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/straccum.hh	2018-02-23 12:47:54.078972078 -0500
@@ -20,143 +20,41 @@ template<typename T> class Vector;
 
 class StringAccum { public:
 
-    /** @brief Construct an empty StringAccum (with length 0). */
-    StringAccum()
-	: _s(0), _len(0), _cap(0) {
-    }
-
-    /** @brief Construct a StringAccum with room for at least @a capacity
-     * characters.
-     * @param capacity initial capacity
-     *
-     * If @a capacity <= 0, the StringAccum is created empty.  If @a capacity
-     * is too large (so that @a capacity bytes of memory can't be allocated),
-     * the StringAccum falls back to a smaller capacity (possibly zero). */
-    explicit inline StringAccum(int capacity);
-
-    /** @brief Construct a StringAccum containing the characters in @a s. */
-    explicit inline StringAccum(const char *cstr)
-	: _s(0), _len(0), _cap(0) {
-	append(cstr);
-    }
-
-    /** @brief Construct a StringAccum containing the characters in @a s. */
-    inline StringAccum(const char *s, int len)
-	: _s(0), _len(0), _cap(0) {
-	append(s, len);
-    }
-
-    /** @brief Construct a StringAccum containing the characters in @a str. */
-    StringAccum(const String &str)
-	: _s(0), _len(0), _cap(0) {
-	append(str.begin(), str.end());
-    }
-
-    /** @brief Construct a StringAccum containing a copy of @a x. */
-    StringAccum(const StringAccum &x)
-	: _s(0), _len(0), _cap(0) {
-	append(x.data(), x.length());
-    }
-
-    /** @brief Destroy a StringAccum, freeing its memory. */
-    ~StringAccum() {
-	if (_cap > 0)
-	    delete[] (_s - MEMO_SPACE);
-    }
-
-
-    /** @brief Return the contents of the StringAccum.
-     * @return The StringAccum's contents.
-     *
-     * The return value is null if the StringAccum is empty or out-of-memory.
-     * The returned data() value points to writable memory (unless the
-     * StringAccum itself is const). */
-    inline const char *data() const {
-	return reinterpret_cast<const char *>(_s);
-    }
-
-    /** @overload */
-    inline char *data() {
-	return reinterpret_cast<char *>(_s);
-    }
+    typedef const char* const_iterator;
+    typedef char* iterator;
 
-    inline const unsigned char* udata() const {
-	return _s;
-    }
-
-    inline unsigned char* udata() {
-	return _s;
-    }
-
-    /** @brief Return true iff the StringAccum is empty or out-of-memory. */
-    bool empty() const {
-	return _len == 0;
-    }
-
-    /** @brief Return the length of the StringAccum. */
-    int length() const {
-	return _len;
-    }
-
-    /** @brief Return the StringAccum's current capacity.
-     *
-     * The capacity is the maximum length the StringAccum can hold without
-     * incurring a memory allocation.  Returns -1 for out-of-memory
-     * StringAccums. */
-    int capacity() const {
-	return _cap;
-    }
-
-
-    typedef const char *const_iterator;
-    typedef char *iterator;
-
-    /** @brief Return an iterator for the first character in the StringAccum.
-     *
-     * StringAccum iterators are simply pointers into string data, so they are
-     * quite efficient.  @sa StringAccum::data */
-    inline const_iterator begin() const {
-	return reinterpret_cast<char *>(_s);
-    }
-
-    /** @overload */
-    inline iterator begin() {
-	return reinterpret_cast<char *>(_s);
-    }
-
-    /** @brief Return an iterator for the end of the StringAccum.
-     *
-     * The return value points one character beyond the last character in the
-     * StringAccum. */
-    inline StringAccum::const_iterator end() const {
-	return reinterpret_cast<char *>(_s + _len);
-    }
-
-    /** @overload */
-    inline iterator end() {
-	return reinterpret_cast<char *>(_s + _len);
-    }
+    typedef int (StringAccum::*unspecified_bool_type)() const;
 
+    inline StringAccum();
+    explicit inline StringAccum(int capacity);
+    explicit inline StringAccum(const char *cstr);
+    inline StringAccum(const char* s, int len);
+    inline StringAccum(const String& str);
+    inline StringAccum(const StringAccum& x);
+    inline ~StringAccum();
+
+    inline const char* data() const;
+    inline char* data();
+    inline const unsigned char* udata() const;
+    inline unsigned char* udata();
+    inline int length() const;
+    inline int capacity() const;
+
+    inline bool empty() const;
+    inline bool operator!() const;
+    inline bool out_of_memory() const;
+
+    inline const_iterator begin() const;
+    inline iterator begin();
+    inline const_iterator end() const;
+    inline iterator end();
 
-    typedef int (StringAccum::*unspecified_bool_type)() const;
 
     /** @brief Return true iff the StringAccum contains characters.
      *
      * Returns false for empty and out-of-memory StringAccums. */
-    operator unspecified_bool_type() const {
-	return _len != 0 ? &StringAccum::capacity : 0;
-    }
-
-    /** @brief Return true iff the StringAccum does not contain characters.
-     *
-     * Returns true for empty and out-of-memory StringAccums. */
-    bool operator!() const {
-	return _len == 0;
-    }
-
-    /** @brief Return true iff the StringAccum is out-of-memory. */
-    bool out_of_memory() const {
-	return _cap < 0;
+    inline operator unspecified_bool_type() const {
+        return _len != 0 ? &StringAccum::capacity : 0;
     }
 
 
@@ -169,182 +67,44 @@ class StringAccum { public:
     const char *c_str();
 
 
-    /** @brief Return the <a>i</a>th character in the string.
-     * @param i character index
-     * @pre 0 <= @a i < length() */
-    char operator[](int i) const {
-	assert((unsigned) i < (unsigned) _len);
-	return static_cast<char>(_s[i]);
-    }
-
-    /** @brief Return a reference to the <a>i</a>th character in the string.
-     * @param i character index
-     * @pre 0 <= @a i < length() */
-    char &operator[](int i) {
-	assert((unsigned) i < (unsigned) _len);
-	return reinterpret_cast<char &>(_s[i]);
-    }
-
-    /** @brief Return the first character in the string.
-     * @pre length() > 0 */
-    char front() const {
-	assert(_len > 0);
-	return static_cast<char>(_s[0]);
-    }
+    inline char operator[](int i) const;
+    inline char& operator[](int i);
+    inline char front() const;
+    inline char& front();
+    inline char back() const;
+    inline char& back();
 
-    /** @brief Return a reference to the first character in the string.
-     * @pre length() > 0 */
-    char &front() {
-	assert(_len > 0);
-	return reinterpret_cast<char &>(_s[0]);
-    }
-
-    /** @brief Return the last character in the string.
-     * @pre length() > 0 */
-    char back() const {
-	assert(_len > 0);
-	return static_cast<char>(_s[_len - 1]);
-    }
-
-    /** @brief Return a reference to the last character in the string.
-     * @pre length() > 0 */
-    char &back() {
-	assert(_len > 0);
-	return reinterpret_cast<char &>(_s[_len - 1]);
-    }
+    inline void clear();
 
-
-    /** @brief Clear the StringAccum's comments.
-     *
-     * All characters in the StringAccum are erased.  Also resets the
-     * StringAccum's out-of-memory status. */
-    inline void clear() {
-	if (_cap < 0) {
-	    _cap = 0;
-	    _s = 0;
-	}
-	_len = 0;
-    }
-
-
-    /** @brief Reserve space for at least @a n characters.
-     * @return a pointer to at least @a n characters, or null if allocation
-     * fails
-     * @pre @a n >= 0
-     *
-     * reserve() does not change the string's length(), only its capacity().
-     * In a frequent usage pattern, code calls reserve(), passing an upper
-     * bound on the characters that could be written by a series of
-     * operations.  After writing into the returned buffer, adjust_length() is
-     * called to account for the number of characters actually written.
-     *
-     * On failure, null is returned and errno is set to ENOMEM. */
-    inline char *reserve(int n) {
-	assert(n >= 0);
-	if (_len + n <= _cap)
-	    return reinterpret_cast<char *>(_s + _len);
-	else
-	    return grow(_len + n);
-    }
-
-    /** @brief Set the StringAccum's length to @a len.
-     * @param len new length in characters
-     * @pre 0 <= @a len <= capacity()
-     * @sa adjust_length */
-    inline void set_length(int len) {
-	assert(len >= 0 && _len <= _cap);
-	_len = len;
-    }
+    inline char* reserve(int n);
+    inline void set_length(int len);
 
     /** @brief Set the StringAccum's length to @a len.
      * @pre @a len >= 0
      * @return 0 on success, -ENOMEM on failure */
     int resize(int len);
 
-    /** @brief Adjust the StringAccum's length.
-     * @param delta  length adjustment
-     * @pre If @a delta > 0, then length() + @a delta <= capacity().
-     *      If @a delta < 0, then length() + delta >= 0.
-     *
-     * The StringAccum's length after adjust_length(@a delta) equals its old
-     * length plus @a delta.  Generally adjust_length() is used after a call
-     * to reserve().  @sa set_length */
-    inline void adjust_length(int delta) {
-	assert(_len + delta >= 0 && _len + delta <= _cap);
-	_len += delta;
-    }
-
-    /** @brief Reserve space and adjust length in one operation.
-     * @param nadjust number of characters to reserve and adjust length
-     * @param nreserve additional characters to reserve
-     * @pre @a nadjust >= 0 and @a nreserve >= 0
-     *
-     * This operation combines the effects of reserve(@a nadjust + @a
-     * nreserve) and adjust_length(@a nadjust).  Returns the result of the
-     * reserve() call. */
-    inline char *extend(int nadjust, int nreserve = 0) {
-	assert(nadjust >= 0 && nreserve >= 0);
-	if (_len + nadjust + nreserve <= _cap) {
-	    char *x = reinterpret_cast<char *>(_s + _len);
-	    _len += nadjust;
-	    return x;
-	} else
-	    return hard_extend(nadjust, nreserve);
-    }
-
-
-    /** @brief Remove characters from the end of the StringAccum.
-     * @param n number of characters to remove
-     * @pre @a n >= 0 and @a n <= length()
-     *
-     * Same as adjust_length(-@a n). */
-    inline void pop_back(int n = 1) {
-	assert(n >= 0 && _len >= n);
-	_len -= n;
-    }
+    inline void adjust_length(int delta);
+    inline char* extend(int nadjust, int nreserve = 0);
 
+    inline void pop_back(int n = 1);
 
 
-    /** @brief Append character @a c to the StringAccum.
-     * @param c character to append */
-    inline void append(char c) {
-	if (_len < _cap || grow(_len))
-	    _s[_len++] = c;
-    }
-    /** @overload */
-    inline void append(unsigned char c) {
-	append(static_cast<char>(c));
-    }
+    inline void append(char c);
+    inline void append(unsigned char c);
 
     /** @brief Append @a len copies of character @a c to the StringAccum. */
     void append_fill(int c, int len);
 
-    /** @brief Append the UTF-8 encoding of Unicode character @a ch. */
-    inline void append_utf8(unsigned ch) {
-	if (ch < 0x80)
-	    append((unsigned char) ch);
-	else
-	    append_utf8_hard(ch);
-    }
+    inline void append_utf8(unsigned ch);
 
     /** @brief Append the null-terminated C string @a s to this StringAccum.
      * @param s data to append */
-    void append(const char *s);
-    /** @brief Append the first @a len characters of @a s to this StringAccum.
-     * @param s data to append
-     * @param len length of data
-     * @pre @a len >= 0 */
-    inline void append(const char *s, int len);
-    /** @overload */
-    inline void append(const unsigned char *s, int len);
-
-    /** @brief Append the data from @a begin to @a end to the end of this
-     * StringAccum.
-     *
-     * Does nothing if @a begin >= @a end. */
-    inline void append(const char *begin, const char *end);
-    /** @overload */
-    inline void append(const unsigned char *begin, const unsigned char *end);
+    void append(const char* s);
+    inline void append(const char* s, int len);
+    inline void append(const unsigned char* s, int len);
+    inline void append(const char* begin, const char* end);
+    inline void append(const unsigned char* begin, const unsigned char* end);
 
     // word joining
     void append_break_lines(const String &text, int linelen, const String &leftmargin = String());
@@ -374,16 +134,7 @@ class StringAccum { public:
     String take_string();
 
 
-    /** @brief Assign this StringAccum to @a x. */
-    StringAccum &operator=(const StringAccum &x) {
-	if (&x != this) {
-	    if (out_of_memory())
-		_s = 0, _cap = 0;
-	    _len = 0;
-	    append(x.data(), x.length());
-	}
-	return *this;
-    }
+    inline StringAccum& operator=(const StringAccum& x);
 
     /** @brief Swap this StringAccum's contents with @a x. */
     void swap(StringAccum &x);
@@ -393,7 +144,7 @@ class StringAccum { public:
   private:
 
     enum {
-	MEMO_SPACE = String::MEMO_SPACE
+        MEMO_SPACE = String::MEMO_SPACE
     };
 
     unsigned char *_s;
@@ -434,42 +185,329 @@ StringAccum &operator<<(StringAccum &, u
 StringAccum &operator<<(StringAccum &, double);
 
 
-inline
-StringAccum::StringAccum(int capacity)
-    : _len(0)
-{
+/** @brief Construct an empty StringAccum (with length 0). */
+inline StringAccum::StringAccum()
+    : _s(0), _len(0), _cap(0) {
+}
+
+/** @brief Construct a StringAccum with room for at least @a capacity
+ * characters.
+ * @param capacity initial capacity
+ *
+ * If @a capacity <= 0, the StringAccum is created empty.  If @a capacity
+ * is too large (so that @a capacity bytes of memory can't be allocated),
+ * the StringAccum falls back to a smaller capacity (possibly zero). */
+inline StringAccum::StringAccum(int capacity)
+    : _len(0) {
     assert(capacity >= 0);
     if (capacity
-	&& (_s = new unsigned char[capacity + MEMO_SPACE])) {
-	_s += MEMO_SPACE;
-	_cap = capacity;
+        && (_s = new unsigned char[capacity + MEMO_SPACE])) {
+        _s += MEMO_SPACE;
+        _cap = capacity;
     } else {
-	_s = 0;
-	_cap = 0;
+        _s = 0;
+        _cap = 0;
     }
 }
 
-inline void StringAccum::append(const char *s, int len) {
+/** @brief Construct a StringAccum containing the characters in @a s. */
+inline StringAccum::StringAccum(const char *cstr)
+    : _s(0), _len(0), _cap(0) {
+    append(cstr);
+}
+
+/** @brief Construct a StringAccum containing the characters in @a s. */
+inline StringAccum::StringAccum(const char *s, int len)
+    : _s(0), _len(0), _cap(0) {
+    append(s, len);
+}
+
+/** @brief Construct a StringAccum containing the characters in @a str. */
+inline StringAccum::StringAccum(const String &str)
+    : _s(0), _len(0), _cap(0) {
+    append(str.begin(), str.end());
+}
+
+/** @brief Construct a StringAccum containing a copy of @a x. */
+inline StringAccum::StringAccum(const StringAccum &x)
+    : _s(0), _len(0), _cap(0) {
+    append(x.data(), x.length());
+}
+
+/** @brief Destroy a StringAccum, freeing its memory. */
+inline StringAccum::~StringAccum() {
+    if (_cap > 0)
+        delete[] (_s - MEMO_SPACE);
+}
+
+/** @brief Return the contents of the StringAccum.
+ * @return The StringAccum's contents.
+ *
+ * The return value is null if the StringAccum is empty or out-of-memory.
+ * The returned data() value points to writable memory (unless the
+ * StringAccum itself is const). */
+inline const char* StringAccum::data() const {
+    return reinterpret_cast<const char *>(_s);
+}
+
+/** @overload */
+inline char* StringAccum::data() {
+    return reinterpret_cast<char *>(_s);
+}
+
+inline const unsigned char* StringAccum::udata() const {
+    return _s;
+}
+
+inline unsigned char* StringAccum::udata() {
+    return _s;
+}
+
+/** @brief Return true iff the StringAccum is empty or out-of-memory. */
+inline bool StringAccum::empty() const {
+    return _len == 0;
+}
+
+/** @brief Return the length of the StringAccum. */
+inline int StringAccum::length() const {
+    return _len;
+}
+
+/** @brief Return the StringAccum's current capacity.
+ *
+ * The capacity is the maximum length the StringAccum can hold without
+ * incurring a memory allocation.  Returns -1 for out-of-memory
+ * StringAccums. */
+inline int StringAccum::capacity() const {
+    return _cap;
+}
+
+/** @brief Return an iterator for the first character in the StringAccum.
+ *
+ * StringAccum iterators are simply pointers into string data, so they are
+ * quite efficient.  @sa StringAccum::data */
+inline StringAccum::const_iterator StringAccum::begin() const {
+    return reinterpret_cast<char*>(_s);
+}
+
+/** @overload */
+inline StringAccum::iterator StringAccum::begin() {
+    return reinterpret_cast<char*>(_s);
+}
+
+/** @brief Return an iterator for the end of the StringAccum.
+ *
+ * The return value points one character beyond the last character in the
+ * StringAccum. */
+inline StringAccum::const_iterator StringAccum::end() const {
+    return reinterpret_cast<char*>(_s + _len);
+}
+
+/** @overload */
+inline StringAccum::iterator StringAccum::end() {
+    return reinterpret_cast<char*>(_s + _len);
+}
+
+/** @brief Return true iff the StringAccum does not contain characters.
+ *
+ * Returns true for empty and out-of-memory StringAccums. */
+inline bool StringAccum::operator!() const {
+    return _len == 0;
+}
+
+/** @brief Return true iff the StringAccum is out-of-memory. */
+inline bool StringAccum::out_of_memory() const {
+    return _cap < 0;
+}
+
+/** @brief Return the <a>i</a>th character in the string.
+ * @param i character index
+ * @pre 0 <= @a i < length() */
+inline char StringAccum::operator[](int i) const {
+    assert((unsigned) i < (unsigned) _len);
+    return static_cast<char>(_s[i]);
+}
+
+/** @brief Return a reference to the <a>i</a>th character in the string.
+ * @param i character index
+ * @pre 0 <= @a i < length() */
+inline char& StringAccum::operator[](int i) {
+    assert((unsigned) i < (unsigned) _len);
+    return reinterpret_cast<char &>(_s[i]);
+}
+
+/** @brief Return the first character in the string.
+ * @pre length() > 0 */
+inline char StringAccum::front() const {
+    assert(_len > 0);
+    return static_cast<char>(_s[0]);
+}
+
+/** @brief Return a reference to the first character in the string.
+ * @pre length() > 0 */
+inline char& StringAccum::front() {
+    assert(_len > 0);
+    return reinterpret_cast<char &>(_s[0]);
+}
+
+/** @brief Return the last character in the string.
+ * @pre length() > 0 */
+inline char StringAccum::back() const {
+    assert(_len > 0);
+    return static_cast<char>(_s[_len - 1]);
+}
+
+/** @brief Return a reference to the last character in the string.
+ * @pre length() > 0 */
+inline char& StringAccum::back() {
+    assert(_len > 0);
+    return reinterpret_cast<char &>(_s[_len - 1]);
+}
+
+/** @brief Clear the StringAccum's comments.
+ *
+ * All characters in the StringAccum are erased.  Also resets the
+ * StringAccum's out-of-memory status. */
+inline void StringAccum::clear() {
+    if (_cap < 0) {
+        _cap = 0;
+        _s = 0;
+    }
+    _len = 0;
+}
+
+/** @brief Reserve space for at least @a n characters.
+ * @return a pointer to at least @a n characters, or null if allocation
+ * fails
+ * @pre @a n >= 0
+ *
+ * reserve() does not change the string's length(), only its capacity().
+ * In a frequent usage pattern, code calls reserve(), passing an upper
+ * bound on the characters that could be written by a series of
+ * operations.  After writing into the returned buffer, adjust_length() is
+ * called to account for the number of characters actually written.
+ *
+ * On failure, null is returned and errno is set to ENOMEM. */
+inline char* StringAccum::reserve(int n) {
+    assert(n >= 0);
+    if (_len + n <= _cap)
+        return reinterpret_cast<char *>(_s + _len);
+    else
+        return grow(_len + n);
+}
+
+/** @brief Set the StringAccum's length to @a len.
+ * @param len new length in characters
+ * @pre 0 <= @a len <= capacity()
+ * @sa adjust_length */
+inline void StringAccum::set_length(int len) {
+    assert(len >= 0 && _len <= _cap);
+    _len = len;
+}
+
+/** @brief Adjust the StringAccum's length.
+ * @param delta  length adjustment
+ * @pre If @a delta > 0, then length() + @a delta <= capacity().
+ *      If @a delta < 0, then length() + delta >= 0.
+ *
+ * The StringAccum's length after adjust_length(@a delta) equals its old
+ * length plus @a delta.  Generally adjust_length() is used after a call
+ * to reserve().  @sa set_length */
+inline void StringAccum::adjust_length(int delta) {
+    assert(_len + delta >= 0 && _len + delta <= _cap);
+    _len += delta;
+}
+
+/** @brief Reserve space and adjust length in one operation.
+ * @param nadjust number of characters to reserve and adjust length
+ * @param nreserve additional characters to reserve
+ * @pre @a nadjust >= 0 and @a nreserve >= 0
+ *
+ * This operation combines the effects of reserve(@a nadjust + @a
+ * nreserve) and adjust_length(@a nadjust).  Returns the result of the
+ * reserve() call. */
+inline char* StringAccum::extend(int nadjust, int nreserve) {
+    assert(nadjust >= 0 && nreserve >= 0);
+    if (_len + nadjust + nreserve <= _cap) {
+        char *x = reinterpret_cast<char *>(_s + _len);
+        _len += nadjust;
+        return x;
+    } else
+        return hard_extend(nadjust, nreserve);
+}
+
+/** @brief Remove characters from the end of the StringAccum.
+ * @param n number of characters to remove
+ * @pre @a n >= 0 and @a n <= length()
+ *
+ * Same as adjust_length(-@a n). */
+inline void StringAccum::pop_back(int n) {
+    assert(n >= 0 && _len >= n);
+    _len -= n;
+}
+
+/** @brief Append character @a c to the StringAccum.
+ * @param c character to append */
+inline void StringAccum::append(char c) {
+    if (_len < _cap || grow(_len))
+        _s[_len++] = c;
+}
+
+/** @overload */
+inline void StringAccum::append(unsigned char c) {
+    append(static_cast<char>(c));
+}
+
+/** @brief Append the UTF-8 encoding of Unicode character @a ch. */
+inline void StringAccum::append_utf8(unsigned ch) {
+    if (ch < 0x80)
+        append((unsigned char) ch);
+    else
+        append_utf8_hard(ch);
+}
+
+/** @brief Append the first @a len characters of @a s to this StringAccum.
+ * @param s data to append
+ * @param len length of data
+ * @pre @a len >= 0 */
+inline void StringAccum::append(const char* s, int len) {
     assert(len >= 0);
     if (_len + len <= _cap) {
-	memcpy(_s + _len, s, len);
-	_len += len;
+        memcpy(_s + _len, s, len);
+        _len += len;
     } else
-	hard_append(s, len);
+        hard_append(s, len);
 }
 
-inline void StringAccum::append(const unsigned char *s, int len) {
+/** @overload */
+inline void StringAccum::append(const unsigned char* s, int len) {
     append(reinterpret_cast<const char *>(s), len);
 }
 
-inline void StringAccum::append(const char *begin, const char *end) {
+/** @brief Append the data from @a begin to @a end to the end of this
+ * StringAccum.
+ *
+ * Does nothing if @a begin >= @a end. */
+inline void StringAccum::append(const char* begin, const char* end) {
     if (begin < end)
-	append(begin, end - begin);
+        append(begin, end - begin);
 }
 
-inline void StringAccum::append(const unsigned char *begin, const unsigned char *end) {
+/** @overload */
+inline void StringAccum::append(const unsigned char* begin, const unsigned char* end) {
     if (begin < end)
-	append(begin, end - begin);
+        append(begin, end - begin);
+}
+
+/** @brief Assign this StringAccum to @a x. */
+inline StringAccum& StringAccum::operator=(const StringAccum& x) {
+    if (&x != this) {
+        if (out_of_memory())
+            _s = 0, _cap = 0;
+        _len = 0;
+        append(x.data(), x.length());
+    }
+    return *this;
 }
 
 /** @relates StringAccum
@@ -513,9 +551,9 @@ operator<<(StringAccum &sa, bool b)
 {
     static const char truefalse[] = "truefalse";
     if (b)
-	sa.append(truefalse, 4);
+        sa.append(truefalse, 4);
     else
-	sa.append(truefalse + 4, 5);
+        sa.append(truefalse + 4, 5);
     return sa;
 }
 
@@ -562,9 +600,9 @@ inline StringAccum &
 operator<<(StringAccum &sa, const String &str)
 {
     if (!str.out_of_memory())
-	sa.hard_append(str.begin(), str.length());
+        sa.hard_append(str.begin(), str.length());
     else
-	sa.assign_out_of_memory();
+        sa.assign_out_of_memory();
     return sa;
 }
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/vector.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/vector.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/vector.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/include/lcdf/vector.cc	2018-02-23 12:47:54.079972053 -0500
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1999-2000 Massachusetts Institute of Technology
  * Copyright (c) 2001-2003 International Computer Science Institute
- * Copyright (c) 1999-2016 Eddie Kohler
+ * Copyright (c) 1999-2018 Eddie Kohler
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/lcdf-typetools.spec.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/lcdf-typetools.spec
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/lcdf-typetools.spec.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/lcdf-typetools.spec	2018-02-23 12:47:54.079972053 -0500
@@ -1,6 +1,6 @@
 Summary: Programs to manipulate OpenType and multiple-master fonts
 Name: lcdf-typetools
-Version: 2.106
+Version: 2.107
 Copyright: GPL
 Vendor: Little Cambridgeport Design Factory <http://www.lcdf.org/>
 Group: Utilities/Printing
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afm.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afm.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afm.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afm.cc	2018-02-23 12:47:54.079972053 -0500
@@ -2,7 +2,7 @@
 
 /* afm.{cc,hh} -- Adobe Font Metrics files
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmparse.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmparse.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmparse.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmparse.cc	2018-02-23 12:47:54.079972053 -0500
@@ -2,7 +2,7 @@
 
 /* afmparse.{cc,hh} -- Adobe Font Metrics parsing
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmw.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmw.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmw.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/afmw.cc	2018-02-23 12:47:54.079972053 -0500
@@ -2,7 +2,7 @@
 
 /* afmw.{cc,hh} -- Adobe Font Metrics writing
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/amfm.cc	2018-02-23 12:47:54.079972053 -0500
@@ -2,7 +2,7 @@
 
 /* amfm.{cc,hh} -- Adobe Multiple-Master Font Metrics
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/cff.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/cff.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/cff.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/cff.cc	2018-02-23 12:47:54.080972028 -0500
@@ -2,7 +2,7 @@
 
 /* cff.{cc,hh} -- Compact Font Format fonts
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -326,17 +326,11 @@ static const uint8_t default_dict_cff_da
     0, 0
 };
 
-static const Cff::Dict &
+static const Cff::Dict&
 default_dict()
 {
-    static Cff *cff;
-    static Cff::Font *cfffont;
-    if (!cfffont) {
-        cff = new Cff(String::make_stable((const char *) default_dict_cff_data, sizeof(default_dict_cff_data)),
-                      0, ErrorHandler::default_handler());
-        cfffont = (Cff::Font *) cff->font();
-    }
-    return cfffont->top_dict();
+    static Cff cff(String::make_stable((const char*) default_dict_cff_data, sizeof(default_dict_cff_data)), 0, ErrorHandler::default_handler());
+    return static_cast<Cff::Font*>(cff.font())->top_dict();
 }
 
 
@@ -360,6 +354,8 @@ Cff::~Cff()
 {
     for (int i = 0; i < _gsubrs_cs.size(); i++)
         delete _gsubrs_cs[i];
+    for (int i = 0; i < _fonts.size(); ++i)
+        delete _fonts[i];
 }
 
 /*
@@ -500,25 +496,6 @@ Cff::sid_permstring(int sid) const
     }
 }
 
-int
-Cff::font_offset(int findex, int &offset, int &length) const
-{
-    if (findex < 0 || findex >= nfonts())
-        return -ENOENT;
-    offset = _top_dict_index[findex] - _data;
-    length = _top_dict_index[findex + 1] - _top_dict_index[findex];
-    return 0;
-}
-
-int
-Cff::font_offset(PermString name, int &offset, int &length) const
-{
-    for (int i = 0; i < _name_index.size(); i++)
-        if (_name_index[i] == name && name)
-            return font_offset(i, offset, length);
-    return -ENOENT;
-}
-
 Cff::FontParent *
 Cff::font(PermString font_name, ErrorHandler *errh)
 {
@@ -529,24 +506,39 @@ Cff::font(PermString font_name, ErrorHan
         return errh->error("invalid CFF"), (FontParent *) 0;
 
     // search for a font named 'font_name'
-    for (int i = 0; i < _name_index.size(); i++)
-        if (_name_index[i] && (!font_name || font_name == _name_index[i])) {
-            int td_offset = _top_dict_index[i] - _data;
-            int td_length = _top_dict_index[i + 1] - _top_dict_index[i];
-            Dict top_dict(this, td_offset, td_length, errh, "Top DICT");
-            if (!top_dict.ok())
-                return 0;
-            else if (top_dict.has_first(oROS))
-                return new Cff::CIDFont(this, _name_index[i], top_dict, errh);
-            else
-                return new Cff::Font(this, _name_index[i], top_dict, errh);
-        }
+    int findex;
+    for (findex = 0; findex < _name_index.size(); ++findex) {
+        if (_name_index[findex]
+            && (!font_name || font_name == _name_index[findex]))
+            break;
+    }
+    if (findex >= _name_index.size()) {
+        if (!font_name)
+            errh->error("no fonts in CFF");
+        else
+            errh->error("font %<%s%> not found", font_name.c_str());
+        return 0;
+    }
+
+    // return font
+    for (int i = 0; i < _fonts.size(); ++i)
+        if (_fonts[i]->_font_index == findex)
+            return _fonts[i];
+
+    int td_offset = _top_dict_index[findex] - _data;
+    int td_length = _top_dict_index[findex + 1] - _top_dict_index[findex];
+    Dict top_dict(this, td_offset, td_length, errh, "Top DICT");
+    if (!top_dict.ok())
+        return 0;
 
-    if (!font_name)
-        errh->error("no fonts in CFF");
+    Cff::FontParent* fp;
+    if (top_dict.has_first(oROS))
+        fp = new Cff::CIDFont(this, _name_index[findex], top_dict, errh);
     else
-        errh->error("font %<%s%> not found", font_name.c_str());
-    return 0;
+        fp = new Cff::Font(this, _name_index[findex], top_dict, errh);
+    fp->_font_index = findex;
+    _fonts.push_back(fp);
+    return fp;
 }
 
 static inline int
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/encoding.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/encoding.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/encoding.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/encoding.cc	2018-02-23 12:47:54.080972028 -0500
@@ -2,7 +2,7 @@
 
 /* encoding.{cc,hh} -- 8-bit encodings
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/findmet.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/findmet.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/findmet.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/findmet.cc	2018-02-23 12:47:54.080972028 -0500
@@ -2,7 +2,7 @@
 
 /* findmet.{cc,hh} -- find font metrics
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/metrics.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/metrics.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/metrics.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/metrics.cc	2018-02-23 12:47:54.080972028 -0500
@@ -2,7 +2,7 @@
 
 /* metrics.{cc,hh} -- generic font metrics
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otf.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otf.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otf.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otf.cc	2018-02-23 12:47:54.080972028 -0500
@@ -2,7 +2,7 @@
 
 /* otf.{cc,hh} -- OpenType font basics
  *
- * Copyright (c) 2002-2016 Eddie Kohler
+ * Copyright (c) 2002-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -747,11 +747,11 @@ FeatureList::lookups(const ScriptList &s
  *                        *
  **************************/
 
-Coverage::Coverage() throw ()
+Coverage::Coverage() noexcept
 {
 }
 
-Coverage::Coverage(Glyph first, Glyph last) throw ()
+Coverage::Coverage(Glyph first, Glyph last) noexcept
 {
     if (first <= last) {
         _str = String("\000\002\000\001\000\000\000\000\000\000", 10);
@@ -764,7 +764,7 @@ Coverage::Coverage(Glyph first, Glyph la
     }
 }
 
-Coverage::Coverage(const Vector<bool> &gmap) throw ()
+Coverage::Coverage(const Vector<bool> &gmap) noexcept
 {
     int end = gmap.size();
     while (end > 0 && !gmap[end - 1])
@@ -790,7 +790,7 @@ Coverage::Coverage(const Vector<bool> &g
     }
 }
 
-Coverage::Coverage(const String &str, ErrorHandler *errh, bool do_check) throw ()
+Coverage::Coverage(const String &str, ErrorHandler *errh, bool do_check) noexcept
     : _str(str)
 {
     _str.align(2);
@@ -844,7 +844,7 @@ Coverage::check(ErrorHandler *errh)
 }
 
 int
-Coverage::size() const throw ()
+Coverage::size() const noexcept
 {
     if (_str.length() == 0)
         return -1;
@@ -861,7 +861,7 @@ Coverage::size() const throw ()
 }
 
 int
-Coverage::coverage_index(Glyph g) const throw ()
+Coverage::coverage_index(Glyph g) const noexcept
 {
     if (_str.length() == 0)
         return -1;
@@ -906,7 +906,7 @@ Coverage::coverage_index(Glyph g) const
 }
 
 Glyph
-Coverage::operator[](int cindex) const throw ()
+Coverage::operator[](int cindex) const noexcept
 {
     if (_str.length() == 0 || cindex < 0)
         return 0;
@@ -935,7 +935,7 @@ Coverage::operator[](int cindex) const t
 }
 
 void
-Coverage::unparse(StringAccum &sa) const throw ()
+Coverage::unparse(StringAccum &sa) const noexcept
 {
     const uint8_t *data = _str.udata();
     if (_str.length() == 0)
@@ -958,7 +958,7 @@ Coverage::unparse(StringAccum &sa) const
 }
 
 String
-Coverage::unparse() const throw ()
+Coverage::unparse() const noexcept
 {
     StringAccum sa;
     unparse(sa);
@@ -1237,7 +1237,7 @@ GlyphSet::operator=(const GlyphSet &o)
  *                        *
  **************************/
 
-ClassDef::ClassDef(const String &str, ErrorHandler *errh) throw ()
+ClassDef::ClassDef(const String &str, ErrorHandler *errh) noexcept
     : _str(str)
 {
     _str.align(2);
@@ -1277,7 +1277,7 @@ ClassDef::check(ErrorHandler *errh)
 }
 
 int
-ClassDef::lookup(Glyph g) const throw ()
+ClassDef::lookup(Glyph g) const noexcept
 {
     if (_str.length() == 0)
         return -1;
@@ -1311,7 +1311,7 @@ ClassDef::lookup(Glyph g) const throw ()
 }
 
 void
-ClassDef::unparse(StringAccum &sa) const throw ()
+ClassDef::unparse(StringAccum &sa) const noexcept
 {
     const uint8_t *data = _str.udata();
     if (_str.length() == 0)
@@ -1336,7 +1336,7 @@ ClassDef::unparse(StringAccum &sa) const
 }
 
 String
-ClassDef::unparse() const throw ()
+ClassDef::unparse() const noexcept
 {
     StringAccum sa;
     unparse(sa);
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfcmap.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfcmap.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfcmap.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfcmap.cc	2018-02-23 12:47:54.080972028 -0500
@@ -2,7 +2,7 @@
 
 /* otfcmap.{cc,hh} -- OpenType cmap table
  *
- * Copyright (c) 2002-2016 Eddie Kohler
+ * Copyright (c) 2002-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -184,25 +184,27 @@ Cmap::check_table(int t, ErrorHandler *e
               || (searchRange>>1) > segCountX2/2
               || 1 << (entrySelector + 1) != searchRange
               || rangeShift != segCountX2 - searchRange)
-              return errh->error("bad table %d segment counts (format 4)", t);
+              return errh->error("bad table %d segment counts (format %d)", format);
           uint32_t segCount = segCountX2 >> 1;
           if (length < 16 + 8 * segCount)
-              return errh->error("bad table %d length (format %d)", t, format);
+              return errh->error("bad table %d length (format %d, length %u, need %u)", t, format, length, 16 + 8 * segCount);
           const uint8_t *endCodes = data + 14;
           const uint8_t *startCodes = endCodes + 2 + segCountX2;
           const uint8_t *idDeltas = startCodes + segCountX2;
           const uint8_t *idRangeOffsets = idDeltas + segCountX2;
+          uint32_t idRangeOffsetsPos = idRangeOffsets - data;
           int last_end = 0;
           for (int i = 0; i < segCountX2; i += 2) {
               int endCode = USHORT_AT(endCodes + i);
               int startCode = USHORT_AT(startCodes + i);
-              /* int idDelta = SHORT_AT(idDeltas + i); // no need to check */
+              /* int idDelta = SHORT_AT(idDeltas + i); // not needed */
               int idRangeOffset = USHORT_AT(idRangeOffsets + i);
               if (endCode < startCode || startCode < last_end)
                   return errh->error("bad table %d overlapping range %d (format %d)", t, i/2, format);
               if (idRangeOffset
-                  && idRangeOffsets + i + idRangeOffset + (endCode - startCode)*2 + 2 > data + length)
-                  return errh->error("bad table %d range %d length (format 4)", t, i/2);
+                  && idRangeOffset != 65535
+                  && idRangeOffsetsPos + i + idRangeOffset + (endCode - startCode)*2 + 2 > length)
+                  return errh->error("bad table %d range %d length (format %d, range %d-%d, idRangeOffset %d, length %u)", t, i/2, format, startCode, endCode, idRangeOffset, length);
               last_end = endCode + 1;
           }
           if (USHORT_AT(endCodes + segCountX2 - 2) != 0xFFFF)
@@ -308,6 +310,8 @@ Cmap::map_table(int t, uint32_t uni, Err
                 int idRangeOffset = USHORT_AT(idRangeOffsets + (m << 1));
                 if (idRangeOffset == 0)
                     return (idDelta + uni) & 65535;
+                else if (idRangeOffset == 65535)
+                    return 0;
                 int g = USHORT_AT(idRangeOffsets + (m << 1) + idRangeOffset + ((uni - startCount) << 1));
                 if (g == 0)
                     return 0;
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdata.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdata.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdata.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdata.cc	2018-02-23 12:47:54.081972003 -0500
@@ -2,7 +2,7 @@
 
 /* otfdata.{cc,hh} -- OpenType bounds-checked string type
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,7 +21,7 @@
 namespace Efont { namespace OpenType {
 
 Data
-Data::subtable(unsigned offset) const throw (Bounds)
+Data::subtable(unsigned offset) const
 {
     if (offset > (unsigned) _str.length())
         throw Bounds();
@@ -29,7 +29,7 @@ Data::subtable(unsigned offset) const th
 }
 
 Data
-Data::offset_subtable(unsigned offset_offset) const throw (Bounds)
+Data::offset_subtable(unsigned offset_offset) const
 {
     int offset = u16(offset_offset);
     if (offset > _str.length())
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdescrip.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdescrip.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdescrip.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfdescrip.cc	2018-02-23 12:47:54.081972003 -0500
@@ -1,6 +1,6 @@
 /* otfdescrip.cc -- descriptions for OpenType tags
  *
- * Copyright (c) 2002-2016 Eddie Kohler
+ * Copyright (c) 2002-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgpos.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgpos.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgpos.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgpos.cc	2018-02-23 12:47:54.081972003 -0500
@@ -2,7 +2,7 @@
 
 /* otfgpos.{cc,hh} -- OpenType GPOS table
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -32,7 +32,7 @@ namespace Efont { namespace OpenType {
  *                        *
  **************************/
 
-Gpos::Gpos(const Data &d, ErrorHandler *errh) throw (Error)
+Gpos::Gpos(const Data &d, ErrorHandler *errh)
 {
     // Fixed    Version
     // Offset   ScriptList
@@ -79,7 +79,7 @@ const int GposValue::nibble_bitcount_x2[
  *                        *
  **************************/
 
-GposLookup::GposLookup(const Data &d) throw (Error)
+GposLookup::GposLookup(const Data &d)
     : _d(d)
 {
     if (_d.length() < 6)
@@ -143,7 +143,7 @@ GposLookup::unparse_automatics(Vector<Po
  *                        *
  **************************/
 
-GposSingle::GposSingle(const Data &d) throw (Error)
+GposSingle::GposSingle(const Data &d)
     : _d(d)
 {
     if (_d[0] != 0
@@ -156,7 +156,7 @@ GposSingle::GposSingle(const Data &d) th
 }
 
 Coverage
-GposSingle::coverage() const throw ()
+GposSingle::coverage() const noexcept
 {
     return Coverage(_d.offset_subtable(2), 0, false);
 }
@@ -183,7 +183,7 @@ GposSingle::unparse(Vector<Positioning>
  *                        *
  **************************/
 
-GposPair::GposPair(const Data &d) throw (Error)
+GposPair::GposPair(const Data &d)
     : _d(d)
 {
     if (_d[0] != 0
@@ -196,7 +196,7 @@ GposPair::GposPair(const Data &d) throw
 }
 
 Coverage
-GposPair::coverage() const throw ()
+GposPair::coverage() const noexcept
 {
     return Coverage(_d.offset_subtable(2), 0, false);
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfgsub.cc	2018-02-23 12:47:54.081972003 -0500
@@ -2,7 +2,7 @@
 
 /* otfgsub.{cc,hh} -- OpenType GSUB table
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -255,13 +255,13 @@ Substitution::context_in(const GlyphSet
 }
 
 Glyph
-Substitution::extract_glyph(const Substitute &s, uint8_t t) throw ()
+Substitution::extract_glyph(const Substitute &s, uint8_t t) noexcept
 {
     return (t == T_GLYPH ? s.gid : 0);
 }
 
 Glyph
-Substitution::extract_glyph(const Substitute &s, int which, uint8_t t) throw ()
+Substitution::extract_glyph(const Substitute &s, int which, uint8_t t) noexcept
 {
     switch (t) {
       case T_GLYPH:
@@ -279,7 +279,7 @@ Substitution::extract_glyph(const Substi
 }
 
 bool
-Substitution::extract_glyphs(const Substitute &s, uint8_t t, Vector<Glyph> &v, bool coverage_ok) throw ()
+Substitution::extract_glyphs(const Substitute &s, uint8_t t, Vector<Glyph> &v, bool coverage_ok) noexcept
 {
     switch (t) {
       case T_GLYPH:
@@ -302,7 +302,7 @@ Substitution::extract_glyphs(const Subst
 }
 
 Glyph *
-Substitution::extract_glyphptr(const Substitute &s, uint8_t t) throw ()
+Substitution::extract_glyphptr(const Substitute &s, uint8_t t) noexcept
 {
     switch (t) {
       case T_GLYPH:
@@ -315,7 +315,7 @@ Substitution::extract_glyphptr(const Sub
 }
 
 int
-Substitution::extract_nglyphs(const Substitute &s, uint8_t t, bool coverage_ok) throw ()
+Substitution::extract_nglyphs(const Substitute &s, uint8_t t, bool coverage_ok) noexcept
 {
     switch (t) {
       case T_GLYPH:
@@ -330,7 +330,7 @@ Substitution::extract_nglyphs(const Subs
 }
 
 bool
-Substitution::matches(const Substitute &s, uint8_t t, int pos, Glyph g) throw ()
+Substitution::matches(const Substitute &s, uint8_t t, int pos, Glyph g) noexcept
 {
     switch (t) {
       case T_GLYPH:
@@ -461,7 +461,7 @@ Substitution::remove_outer_right()
 }
 
 bool
-Substitution::out_alter(const Substitution &o, int pos) throw ()
+Substitution::out_alter(const Substitution &o, int pos) noexcept
 {
     const Glyph *g = out_glyphptr();
     int ng = out_nglyphs();
@@ -490,7 +490,7 @@ Substitution::out_alter(const Substituti
 }
 
 static void
-unparse_glyphid(StringAccum &sa, Glyph gid, const Vector<PermString> *gns) throw ()
+unparse_glyphid(StringAccum &sa, Glyph gid, const Vector<PermString> *gns) noexcept
 {
     if (gid > 0 && gns && gns->size() > gid && (*gns)[gid])
         sa << (*gns)[gid];
@@ -499,7 +499,7 @@ unparse_glyphid(StringAccum &sa, Glyph g
 }
 
 void
-Substitution::unparse_glyphids(StringAccum &sa, const Substitute &s, uint8_t t, const Vector<PermString> *gns) throw ()
+Substitution::unparse_glyphids(StringAccum &sa, const Substitute &s, uint8_t t, const Vector<PermString> *gns) noexcept
 {
     if (t == T_GLYPH)
         unparse_glyphid(sa, s.gid, gns);
@@ -565,7 +565,7 @@ Substitution::unparse(const Vector<PermS
  *                        *
  **************************/
 
-Gsub::Gsub(const Data &d, const Font *otf, ErrorHandler *errh) throw (Error)
+Gsub::Gsub(const Data &d, const Font *otf, ErrorHandler *errh)
     : _chaincontext_reverse_backtrack(false)
 {
     // Fixed    Version
@@ -615,7 +615,7 @@ Gsub::lookup(unsigned i) const
  *                        *
  **************************/
 
-GsubLookup::GsubLookup(const Data &d) throw (Error)
+GsubLookup::GsubLookup(const Data &d)
     : _d(d)
 {
     if (_d.length() < 6)
@@ -779,7 +779,7 @@ GsubLookup::apply(const Glyph *g, int po
  *                        *
  **************************/
 
-GsubSingle::GsubSingle(const Data &d) throw (Error)
+GsubSingle::GsubSingle(const Data &d)
     : _d(d)
 {
     if (_d[0] != 0
@@ -792,7 +792,7 @@ GsubSingle::GsubSingle(const Data &d) th
 }
 
 Coverage
-GsubSingle::coverage() const throw ()
+GsubSingle::coverage() const noexcept
 {
     return Coverage(_d.offset_subtable(2), 0, false);
 }
@@ -857,7 +857,7 @@ GsubSingle::apply(const Glyph *g, int po
  *                        *
  **************************/
 
-GsubMultiple::GsubMultiple(const Data &d) throw (Error)
+GsubMultiple::GsubMultiple(const Data &d)
     : _d(d)
 {
     if (_d[0] != 0 || _d[1] != 1)
@@ -869,7 +869,7 @@ GsubMultiple::GsubMultiple(const Data &d
 }
 
 Coverage
-GsubMultiple::coverage() const throw ()
+GsubMultiple::coverage() const noexcept
 {
     return Coverage(_d.offset_subtable(2), 0, false);
 }
@@ -934,7 +934,7 @@ GsubMultiple::apply(const Glyph *g, int
  *                        *
  **************************/
 
-GsubLigature::GsubLigature(const Data &d) throw (Error)
+GsubLigature::GsubLigature(const Data &d)
     : _d(d)
 {
     if (_d[0] != 0
@@ -947,7 +947,7 @@ GsubLigature::GsubLigature(const Data &d
 }
 
 Coverage
-GsubLigature::coverage() const throw ()
+GsubLigature::coverage() const noexcept
 {
     return Coverage(_d.offset_subtable(2), 0, false);
 }
@@ -1040,7 +1040,7 @@ GsubLigature::apply(const Glyph *g, int
  *                        *
  **************************/
 
-GsubContext::GsubContext(const Data &d) throw (Error)
+GsubContext::GsubContext(const Data &d)
     : _d(d)
 {
     switch (_d.u16(0)) {
@@ -1062,7 +1062,7 @@ GsubContext::GsubContext(const Data &d)
 }
 
 Coverage
-GsubContext::coverage() const throw ()
+GsubContext::coverage() const noexcept
 {
     if (_d[1] == 3)
         return Coverage(_d.offset_subtable(F3_HSIZE), 0, false);
@@ -1171,7 +1171,7 @@ GsubContext::unparse(const Gsub &gsub, V
  *                        *
  **************************/
 
-GsubChainContext::GsubChainContext(const Data &d) throw (Error)
+GsubChainContext::GsubChainContext(const Data &d)
     : _d(d)
 {
     switch (_d.u16(0)) {
@@ -1201,7 +1201,7 @@ GsubChainContext::GsubChainContext(const
 }
 
 Coverage
-GsubChainContext::coverage() const throw ()
+GsubChainContext::coverage() const noexcept
 {
     switch (_d.u16(0)) {
     case 1:
@@ -1279,7 +1279,6 @@ GsubChainContext::f1_unparse(const Gsub
             int subtab_offset = subst_offset + 2;
 
             Substitution s(nbacktrack, ninput, ninput, nlookahead);
-            Glyph* left_begin = s.left_glyphptr();
             if (gsub.chaincontext_reverse_backtrack()) {
                 for (int i = 0; i != nbacktrack; ++i)
                     s.left_glyphptr()[i] = _d.u16(sr_offset + 2 + i*2);
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfname.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfname.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfname.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfname.cc	2018-02-23 12:47:54.081972003 -0500
@@ -2,7 +2,7 @@
 
 /* otfname.{cc,hh} -- OpenType name table
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfos2.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfos2.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfos2.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfos2.cc	2018-02-23 12:47:54.081972003 -0500
@@ -2,7 +2,7 @@
 
 /* otfos2.{cc,hh} -- OpenType OS/2 table
  *
- * Copyright (c) 2005-2016 Eddie Kohler
+ * Copyright (c) 2005-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfpost.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfpost.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfpost.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/otfpost.cc	2018-02-23 12:47:54.082971978 -0500
@@ -2,7 +2,7 @@
 
 /* otfpost.{cc,hh} -- OpenType post table
  *
- * Copyright (c) 2006-2016 Eddie Kohler
+ * Copyright (c) 2006-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/pairop.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/pairop.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/pairop.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/pairop.cc	2018-02-23 12:47:54.082971978 -0500
@@ -2,7 +2,7 @@
 
 /* pairop.{cc,hh} -- ligature/kern font metrics
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/psres.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/psres.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/psres.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/psres.cc	2018-02-23 12:47:54.082971978 -0500
@@ -2,7 +2,7 @@
 
 /* psres.{cc,hh} -- PSres.upr files
  *
- * Copyright (c) 1999-2016 Eddie Kohler
+ * Copyright (c) 1999-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1bounds.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1bounds.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1bounds.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1bounds.cc	2018-02-23 12:47:54.082971978 -0500
@@ -2,7 +2,7 @@
 
 /* t1bounds.{cc,hh} -- charstring bounding box finder
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1cs.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1cs.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1cs.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1cs.cc	2018-02-23 12:47:54.082971978 -0500
@@ -2,7 +2,7 @@
 
 /* t1cs.{cc,hh} -- Type 1/2 charstrings
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -115,7 +115,7 @@ Type1Charstring::Type1Charstring(int len
         const unsigned char *d = reinterpret_cast<const unsigned char*>(s.data());
         _key = t1R_cs;
         for (int i = 0; i < lenIV; i++, d++)
-            _key = ((*d + _key) * t1C1 + t1C2) & 0xFFFF;
+            _key = ((*d + _key) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
         _s = s.substring(lenIV);
     }
 }
@@ -139,7 +139,7 @@ Type1Charstring::decrypt() const
         for (int i = 0; i < _s.length(); i++, d++) {
             uint8_t encrypted = *d;
             *d = encrypted ^ (r >> 8);
-            r = ((encrypted + r) * t1C1 + t1C2) & 0xFFFF;
+            r = ((encrypted + r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
         }
         _key = -1;
     }
@@ -193,7 +193,7 @@ Type1Charstring::process(CharstringInter
         } else {                                        // 255: push huge number
             if (left < 5)
                 goto runoff_error;
-            int32_t val = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
+            int32_t val = ((uint32_t) data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
             more = interp.number(val);
             ahead = 5;
         }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1csgen.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1csgen.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1csgen.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1csgen.cc	2018-02-23 12:47:54.082971978 -0500
@@ -2,7 +2,7 @@
 
 /* t1csgen.{cc,hh} -- Type 1 charstring generation
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1font.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1font.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1font.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1font.cc	2018-02-23 12:47:54.082971978 -0500
@@ -2,7 +2,7 @@
 
 /* t1font.{cc,hh} -- Type 1 font
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1fontskel.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1fontskel.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1fontskel.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1fontskel.cc	2018-02-23 12:47:54.083971953 -0500
@@ -1,6 +1,6 @@
 /* t1fontskel.cc -- Type 1 font skeleton
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1interp.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1interp.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1interp.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1interp.cc	2018-02-23 12:47:54.083971953 -0500
@@ -2,7 +2,7 @@
 
 /* t1interp.{cc,hh} -- Type 1/2 charstring interpretation
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1item.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1item.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1item.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1item.cc	2018-02-23 12:47:54.083971953 -0500
@@ -2,7 +2,7 @@
 
 /* t1item.{cc,hh} -- items in a Type 1 font
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -731,12 +731,12 @@ Type1Subr::gen(Type1Writer &w)
         for (int i = 0; i < w.lenIV(); i++) {
             unsigned char c = (unsigned char)(r >> 8);
             *t++ = c;
-            r = ((c + r) * t1C1 + t1C2) & 0xFFFF;
+            r = ((c + r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
         }
         for (int i = 0; i < len; i++, data++) {
             unsigned char c = (*data ^ (r >> 8));
             *t++ = c;
-            r = ((c + r) * t1C1 + t1C2) & 0xFFFF;
+            r = ((c + r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
         }
 
         w.print((char *)buf, len + w.lenIV());
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1mm.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1mm.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1mm.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1mm.cc	2018-02-23 12:47:54.083971953 -0500
@@ -2,7 +2,7 @@
 
 /* t1mm.{cc,hh} -- Type 1 multiple master font information
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1rw.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1rw.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1rw.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1rw.cc	2018-02-23 12:47:54.083971953 -0500
@@ -2,7 +2,7 @@
 
 /* t1rw.{cc,hh} -- Type 1 font reading and writing
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -117,7 +117,7 @@ inline int
 Type1Reader::eexec(int c)
 {
     unsigned char answer = (unsigned char)(c ^ (_r >> 8));
-    _r = (((unsigned char)c + _r) * t1C1 + t1C2) & 0xFFFF;
+    _r = (((unsigned char)c + _r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
     return answer;
 }
 
@@ -439,7 +439,7 @@ inline unsigned char
 Type1Writer::eexec(int p)
 {
     unsigned char c = ((unsigned char)p ^ (_r >> 8)) & 0xFF;
-    _r = ((c + _r) * t1C1 + t1C2) & 0xFFFF;
+    _r = ((c + _r) * (uint32_t) t1C1 + t1C2) & 0xFFFF;
     return c;
 }
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1unparser.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1unparser.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1unparser.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/t1unparser.cc	2018-02-23 12:47:54.083971953 -0500
@@ -2,7 +2,7 @@
 
 /* t1unparser.{cc,hh} -- debug printing of Type 1 fonts
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfcs.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfcs.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfcs.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfcs.cc	2018-02-23 12:47:54.084971928 -0500
@@ -2,7 +2,7 @@
 
 /* ttfcs.{cc,hh} -- TrueType "charstring" emulation
  *
- * Copyright (c) 2006-2016 Eddie Kohler
+ * Copyright (c) 2006-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfhead.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfhead.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfhead.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfhead.cc	2018-02-23 12:47:54.084971928 -0500
@@ -2,7 +2,7 @@
 
 /* ttfhead.{cc,hh} -- TrueType head table
  *
- * Copyright (c) 2007-2016 Eddie Kohler
+ * Copyright (c) 2007-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfkern.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfkern.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfkern.cc.git4166ff9	2016-11-25 13:08:52.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/libefont/ttfkern.cc	2018-02-23 12:47:54.084971928 -0500
@@ -2,7 +2,7 @@
 
 /* ttfkern.{cc,hh} -- TrueType kern table
  *
- * Copyright (c) 2009-2016 Eddie Kohler
+ * Copyright (c) 2009-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -27,7 +27,7 @@
 namespace Efont { namespace OpenType {
 
 inline Data
-KernTable::subtable(uint32_t &off_in_out) const throw (Error)
+KernTable::subtable(uint32_t &off_in_out) const
 {
     uint32_t off = off_in_out, len;
     if (_version == 0) {
@@ -42,7 +42,7 @@ KernTable::subtable(uint32_t &off_in_out
     return _d.substring(off, len);
 }
 
-KernTable::KernTable(const Data &d, ErrorHandler *) throw (Error)
+KernTable::KernTable(const Data &d, ErrorHandler *)
     : _d(d), _error(-1)
 {
     // USHORT   Version
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/bezier.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/bezier.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/bezier.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/bezier.cc	2018-02-23 12:47:54.084971928 -0500
@@ -2,7 +2,7 @@
 
 /* bezier.{cc,hh} -- cubic Bezier curves
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -23,7 +23,7 @@
 //
 
 void
-Bezier::make_bb() const throw ()
+Bezier::make_bb() const noexcept
 {
     _bb = 0;
     for (int i = 1; i < 4; i++) {
@@ -44,7 +44,7 @@ Bezier::make_bb() const throw ()
 //
 
 bool
-Bezier::is_flat(double t) const throw ()
+Bezier::is_flat(double t) const noexcept
 {
     return (_p[2].on_segment(_p[0], _p[3], t)
 	    && _p[1].on_segment(_p[0], _p[3], t));
@@ -66,7 +66,7 @@ eval_bezier(Point *b_in, int degree, dou
 }
 
 Point
-Bezier::eval(double u) const throw ()
+Bezier::eval(double u) const noexcept
 {
     Bezier b = *this;
     double m = 1.0 - u;
@@ -82,7 +82,7 @@ Bezier::eval(double u) const throw ()
 //
 
 void
-Bezier::halve(Bezier &l, Bezier &r) const throw ()
+Bezier::halve(Bezier &l, Bezier &r) const noexcept
 {
     Point half = Point::midpoint(_p[1], _p[2]);
     l._p[0] = _p[0];
@@ -100,7 +100,7 @@ Bezier::halve(Bezier &l, Bezier &r) cons
 //
 
 bool
-Bezier::in_bb(const Point &p, double tolerance) const throw ()
+Bezier::in_bb(const Point &p, double tolerance) const noexcept
 {
     ensure_bb();
     if (bb_right() + tolerance < p.x
@@ -114,7 +114,7 @@ Bezier::in_bb(const Point &p, double tol
 
 double
 Bezier::hit_recurse(const Point &p, double tolerance, double leftd,
-		    double rightd, double leftt, double rightt) const throw ()
+		    double rightd, double leftt, double rightt) const noexcept
 {
     Bezier left, right;
     double middled, resultt;
@@ -146,7 +146,7 @@ Bezier::hit_recurse(const Point &p, doub
 }
 
 bool
-Bezier::hit(const Point &p, double tolerance) const throw ()
+Bezier::hit(const Point &p, double tolerance) const noexcept
 {
     double leftd = (_p[0] - p).squared_length();
     double rightd = (_p[3] - p).squared_length();
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c	2018-02-23 12:47:54.084971928 -0500
@@ -2,7 +2,7 @@
 /* clp.c - Complete source code for CLP.
  * This file is part of CLP, the command line parser package.
  *
- * Copyright (c) 1997-2016 Eddie Kohler, ekohler@gmail.com
+ * Copyright (c) 1997-2018 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"),
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/error.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/error.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/error.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/error.cc	2018-02-23 12:47:54.085971903 -0500
@@ -4,7 +4,7 @@
  * Eddie Kohler
  *
  * Copyright (c) 1999-2000 Massachusetts Institute of Technology
- * Copyright (c) 2001-2016 Eddie Kohler
+ * Copyright (c) 2001-2018 Eddie Kohler
  * Copyright (c) 2008 Meraki, Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -595,7 +595,7 @@ ErrorHandler::vxformat(int default_flags
 
 	    s2 = numbuf + NUMBUF_SIZE;
 
-	    unsigned long num;
+	    do_number_t num;
 	    switch (width_flag) {
 	    case 'H':
 	    case -8:
@@ -651,13 +651,12 @@ ErrorHandler::vxformat(int default_flags
 	    default:
 		goto error;
 	    }
-	    s1 = do_number(num, (char *)s2, base, flags);
+	    s1 = do_number(num, (char*) s2, base, flags);
 
 #if HAVE_INT64_TYPES
 	got_number:
 #endif
-	    s1 = do_number_flags((char *)s1, (char *)s2, base, flags,
-				 precision, field_width);
+	    s1 = do_number_flags((char*)s1, (char*) s2, base, flags, precision, field_width);
 	    break;
 	}
 
@@ -681,7 +680,7 @@ ErrorHandler::vxformat(int default_flags
 	    }
 	    void* v = va_arg(val, void*);
 	    s2 = numbuf + NUMBUF_SIZE;
-	    s1 = do_number((unsigned long) v, (char*) s2, 16, flags);
+	    s1 = do_number((do_number_t) v, (char*) s2, 16, flags);
 	    s1 = do_number_flags((char*) s1, (char*) s2, 16, flags | cf_alternate_form, precision, field_width);
 	    break;
 	}
@@ -828,7 +827,7 @@ ErrorHandler::fatal(const char *fmt, ...
 {
     va_list val;
     va_start(val, fmt);
-    int r = xmessage(String::make_stable(e_fatal, 4), fmt, val);
+    (void) xmessage(String::make_stable(e_fatal, 4), fmt, val);
     va_end(val);
     abort();
 }
@@ -881,7 +880,7 @@ ErrorHandler::lfatal(const String &landm
     va_list val;
     va_start(val, fmt);
     String l = make_landmark_anno(landmark);
-    int r = xmessage(String::make_stable(e_fatal, 4) + l, fmt, val);
+    (void) xmessage(String::make_stable(e_fatal, 4) + l, fmt, val);
     va_end(val);
     abort();
 }
@@ -1091,7 +1090,7 @@ ErrorVeneer::account(int level)
 ContextErrorHandler::ContextErrorHandler(ErrorHandler *errh, const char *fmt,
 					 ...)
     : ErrorVeneer(errh), _indent(String::make_stable("  ", 2)),
-      _context_printed(false), _context_landmark("{l:}")
+      _context_landmark("{l:}"), _context_printed(false)
 {
     va_list val;
     va_start(val, fmt);
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/filename.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/filename.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/filename.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/filename.cc	2018-02-23 12:47:54.085971903 -0500
@@ -2,7 +2,7 @@
 
 /* filename.{cc,hh} -- filenames
  *
- * Copyright (c) 1999-2016 Eddie Kohler
+ * Copyright (c) 1999-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -126,5 +126,5 @@ Filename::open_write(bool binary) const
     if (_actual || !_path)
 	return _actual;
     else
-	return fopen(_path.c_str(), "wb");
+	return fopen(_path.c_str(), binary ? "wb" : "w");
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/globmatch.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/globmatch.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/globmatch.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/globmatch.cc	2018-02-23 12:47:54.085971903 -0500
@@ -2,7 +2,7 @@
 
 /* globmatch.{cc,hh} -- glob_match() function for shell globbing
  *
- * Copyright (c) 2000-2016 Eddie Kohler
+ * Copyright (c) 2000-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/landmark.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/landmark.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/landmark.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/landmark.cc	2018-02-23 12:47:54.085971903 -0500
@@ -2,7 +2,7 @@
 
 /* landmark.{cc,hh} -- FILE:LINE type landmarks
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/permstr.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/permstr.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/permstr.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/permstr.cc	2018-02-23 12:47:54.086971878 -0500
@@ -2,7 +2,7 @@
 
 /* permstr.{cc,hh} -- permanent strings
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/point.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/point.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/point.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/point.cc	2018-02-23 12:47:54.087971853 -0500
@@ -2,7 +2,7 @@
 
 /* point.{cc,hh} -- 2D points
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -19,7 +19,7 @@
 #include <lcdf/point.hh>
 
 Point
-Point::rotated(double rotation) const throw ()
+Point::rotated(double rotation) const noexcept
 {
     double r = length();
     double theta = angle() + rotation;
@@ -27,13 +27,13 @@ Point::rotated(double rotation) const th
 }
 
 Point
-Point::midpoint(const Point &a, const Point &b) throw ()
+Point::midpoint(const Point &a, const Point &b) noexcept
 {
     return Point((a.x + b.x)/2, (a.y + b.y)/2);
 }
 
 bool
-Point::on_line(const Point &a, const Point &b, double tolerance) const throw ()
+Point::on_line(const Point &a, const Point &b, double tolerance) const noexcept
 {
     Point c = b - a;
     double d = c.x * (y - a.y) - c.y * (x - a.x);
@@ -41,7 +41,7 @@ Point::on_line(const Point &a, const Poi
 }
 
 bool
-Point::on_segment(const Point &a, const Point &b, double t) const throw ()
+Point::on_segment(const Point &a, const Point &b, double t) const noexcept
 {
     double tt;
     Point c = b - a;
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/slurper.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/slurper.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/slurper.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/slurper.cc	2018-02-23 12:47:54.087971853 -0500
@@ -2,7 +2,7 @@
 
 /* slurper.{cc,hh} -- reading from files a line at a time
  *
- * Copyright (c) 1998-2016 Eddie Kohler
+ * Copyright (c) 1998-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/straccum.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/straccum.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/straccum.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/straccum.cc	2018-02-23 12:47:54.087971853 -0500
@@ -4,7 +4,7 @@
  * Eddie Kohler
  *
  * Copyright (c) 1999-2000 Massachusetts Institute of Technology
- * Copyright (c) 2001-2016 Eddie Kohler
+ * Copyright (c) 2001-2018 Eddie Kohler
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -61,7 +61,7 @@ StringAccum::assign_out_of_memory()
 {
     assert(_cap >= 0);
     if (_cap > 0)
-	delete[] (_s - MEMO_SPACE);
+        delete[] (_s - MEMO_SPACE);
     _s = reinterpret_cast<unsigned char *>(const_cast<char *>(String::out_of_memory_data()));
     _cap = -1;
     _len = 0;
@@ -72,25 +72,25 @@ StringAccum::grow(int want)
 {
     // can't append to out-of-memory strings
     if (_cap < 0) {
-	errno = ENOMEM;
-	return 0;
+        errno = ENOMEM;
+        return 0;
     }
 
     int ncap = (_cap ? (_cap + MEMO_SPACE) * 2 : 128) - MEMO_SPACE;
     while (ncap <= want)
-	ncap = (ncap + MEMO_SPACE) * 2 - MEMO_SPACE;
+        ncap = (ncap + MEMO_SPACE) * 2 - MEMO_SPACE;
 
     unsigned char *n = new unsigned char[ncap + MEMO_SPACE];
     if (!n) {
-	assign_out_of_memory();
-	errno = ENOMEM;
-	return 0;
+        assign_out_of_memory();
+        errno = ENOMEM;
+        return 0;
     }
     n += MEMO_SPACE;
 
     if (_s) {
-	memcpy(n, _s, _len);
-	delete[] (_s - MEMO_SPACE);
+        memcpy(n, _s, _len);
+        delete[] (_s - MEMO_SPACE);
     }
     _s = n;
     _cap = ncap;
@@ -102,10 +102,10 @@ StringAccum::resize(int len)
 {
     assert(len >= 0);
     if (len > _cap && !grow(len))
-	return -ENOMEM;
+        return -ENOMEM;
     else {
-	_len = len;
-	return 0;
+        _len = len;
+        return 0;
     }
 }
 
@@ -114,7 +114,7 @@ StringAccum::hard_extend(int nadjust, in
 {
     char *x = grow(_len + nadjust + nreserve);
     if (x)
-	_len += nadjust;
+        _len += nadjust;
     return x;
 }
 
@@ -122,7 +122,7 @@ const char *
 StringAccum::c_str()
 {
     if (_len < _cap || grow(_len))
-	_s[_len] = '\0';
+        _s[_len] = '\0';
     return reinterpret_cast<char *>(_s);
 }
 
@@ -130,28 +130,28 @@ void
 StringAccum::append_fill(int c, int len)
 {
     if (char *s = extend(len))
-	memset(s, c, len);
+        memset(s, c, len);
 }
 
 void
 StringAccum::append_utf8_hard(unsigned ch)
 {
     if (ch < 0x80)
-	append((unsigned char) ch);
+        append((unsigned char) ch);
     else if (ch < 0x800) {
-	append((unsigned char) (0xC0 + ((ch >> 6) & 0x1F)));
-	append((unsigned char) (0x80 + (ch & 0x3F)));
+        append((unsigned char) (0xC0 + ((ch >> 6) & 0x1F)));
+        append((unsigned char) (0x80 + (ch & 0x3F)));
     } else if (ch < 0x10000) {
-	append((unsigned char) (0xE0 + ((ch >> 12) & 0x0F)));
-	append((unsigned char) (0x80 + ((ch >> 6) & 0x3F)));
-	append((unsigned char) (0x80 + (ch & 0x3F)));
+        append((unsigned char) (0xE0 + ((ch >> 12) & 0x0F)));
+        append((unsigned char) (0x80 + ((ch >> 6) & 0x3F)));
+        append((unsigned char) (0x80 + (ch & 0x3F)));
     } else if (ch < 0x110000) {
-	append((unsigned char) (0xF0 + ((ch >> 18) & 0x07)));
-	append((unsigned char) (0x80 + ((ch >> 12) & 0x3F)));
-	append((unsigned char) (0x80 + ((ch >> 6) & 0x3F)));
-	append((unsigned char) (0x80 + (ch & 0x3F)));
+        append((unsigned char) (0xF0 + ((ch >> 18) & 0x07)));
+        append((unsigned char) (0x80 + ((ch >> 12) & 0x3F)));
+        append((unsigned char) (0x80 + ((ch >> 6) & 0x3F)));
+        append((unsigned char) (0x80 + (ch & 0x3F)));
     } else
-	append((unsigned char) '?');
+        append((unsigned char) '?');
 }
 
 void
@@ -161,27 +161,29 @@ StringAccum::hard_append(const char *s,
     // a naive implementation might use sa's data after freeing it.
     const char *my_s = reinterpret_cast<char *>(_s);
 
-    if (_len + len <= _cap) {
+    if (len <= 0) {
+        // do nothing
+    } else if (_len + len <= _cap) {
     success:
-	memcpy(_s + _len, s, len);
-	_len += len;
+        memcpy(_s + _len, s, len);
+        _len += len;
     } else if (s < my_s || s >= my_s + _cap) {
-	if (grow(_len + len))
-	    goto success;
+        if (grow(_len + len))
+            goto success;
     } else {
-	unsigned char *old_s = _s;
-	int old_len = _len;
+        unsigned char *old_s = _s;
+        int old_len = _len;
 
-	_s = 0;
-	_len = 0;
-	_cap = 0;
-
-	if (char *new_s = extend(old_len + len)) {
-	    memcpy(new_s, old_s, old_len);
-	    memcpy(new_s + old_len, s, len);
-	}
+        _s = 0;
+        _len = 0;
+        _cap = 0;
+
+        if (char *new_s = extend(old_len + len)) {
+            memcpy(new_s, old_s, old_len);
+            memcpy(new_s + old_len, s, len);
+        }
 
-	delete[] (old_s - MEMO_SPACE);
+        delete[] (old_s - MEMO_SPACE);
     }
 }
 
@@ -198,14 +200,14 @@ StringAccum::take_string()
     int cap = _cap;
     char *str = reinterpret_cast<char *>(_s);
     if (len > 0) {
-	_s = 0;
-	_len = _cap = 0;
-	return String::make_claim(str, len, cap);
+        _s = 0;
+        _len = _cap = 0;
+        return String::make_claim(str, len, cap);
     } else if (!out_of_memory())
-	return String();
+        return String();
     else {
-	clear();
-	return String::make_out_of_memory();
+        clear();
+        return String::make_out_of_memory();
     }
 }
 
@@ -227,8 +229,8 @@ StringAccum &
 operator<<(StringAccum &sa, long i)
 {
     if (char *x = sa.reserve(24)) {
-	int len = sprintf(x, "%ld", i);
-	sa.adjust_length(len);
+        int len = sprintf(x, "%ld", i);
+        sa.adjust_length(len);
     }
     return sa;
 }
@@ -240,8 +242,8 @@ StringAccum &
 operator<<(StringAccum &sa, unsigned long u)
 {
     if (char *x = sa.reserve(24)) {
-	int len = sprintf(x, "%lu", u);
-	sa.adjust_length(len);
+        int len = sprintf(x, "%lu", u);
+        sa.adjust_length(len);
     }
     return sa;
 }
@@ -250,8 +252,8 @@ StringAccum &
 operator<<(StringAccum &sa, double d)
 {
     if (char *x = sa.reserve(256)) {
-	int len = sprintf(x, "%.12g", d);
-	sa.adjust_length(len);
+        int len = sprintf(x, "%.12g", d);
+        sa.adjust_length(len);
     }
     return sa;
 }
@@ -263,12 +265,12 @@ StringAccum::snprintf(int n, const char
     va_start(val, format);
     if (char *x = reserve(n + 1)) {
 #if HAVE_VSNPRINTF
-	int len = vsnprintf(x, n + 1, format, val);
+        int len = vsnprintf(x, n + 1, format, val);
 #else
-	int len = vsprintf(x, format, val);
-	assert(len <= n);
+        int len = vsprintf(x, format, val);
+        assert(len <= n);
 #endif
-	adjust_length(len);
+        adjust_length(len);
     }
     va_end(val);
     return *this;
@@ -278,27 +280,27 @@ void
 StringAccum::append_break_lines(const String& text, int linelen, const String &leftmargin)
 {
     if (text.length() == 0)
-	return;
+        return;
     const char* line = text.begin();
     const char* ends = text.end();
     linelen -= leftmargin.length();
     for (const char* s = line; s < ends; s++) {
-	const char* start = s;
-	while (s < ends && isspace((unsigned char) *s))
-	    s++;
-	const char* word = s;
-	while (s < ends && !isspace((unsigned char) *s))
-	    s++;
-	if (s - line > linelen && start > line) {
-	    *this << leftmargin;
-	    append(line, start - line);
-	    *this << '\n';
-	    line = word;
-	}
+        const char* start = s;
+        while (s < ends && isspace((unsigned char) *s))
+            s++;
+        const char* word = s;
+        while (s < ends && !isspace((unsigned char) *s))
+            s++;
+        if (s - line > linelen && start > line) {
+            *this << leftmargin;
+            append(line, start - line);
+            *this << '\n';
+            line = word;
+        }
     }
     if (line < text.end()) {
-	*this << leftmargin;
-	append(line, text.end() - line);
-	*this << '\n';
+        *this << leftmargin;
+        append(line, text.end() - line);
+        *this << '\n';
     }
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/string.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/string.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/string.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/string.cc	2018-02-23 12:47:54.087971853 -0500
@@ -4,7 +4,7 @@
  * Eddie Kohler
  *
  * Copyright (c) 1999-2000 Massachusetts Institute of Technology
- * Copyright (c) 2001-2016 Eddie Kohler
+ * Copyright (c) 2001-2018 Eddie Kohler
  * Copyright (c) 2008-2009 Meraki, Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/transform.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/transform.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/transform.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/transform.cc	2018-02-23 12:47:54.087971853 -0500
@@ -2,7 +2,7 @@
 
 /* transform.{cc,hh} -- planar affine transformations
  *
- * Copyright (c) 2000-2016 Eddie Kohler
+ * Copyright (c) 2000-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/vectorv.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/vectorv.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/vectorv.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/vectorv.cc	2018-02-23 12:47:54.087971853 -0500
@@ -36,11 +36,11 @@ Vector<void*> &
 Vector<void*>::operator=(const Vector<void*> &o)
 {
     if (&o != this) {
-	_n = 0;
-	if (reserve(o._n)) {
-	    _n = o._n;
-	    memcpy(_l, o._l, sizeof(void *) * _n);
-	}
+        _n = 0;
+        if (reserve(o._n)) {
+            _n = o._n;
+            memcpy(_l, o._l, sizeof(void *) * _n);
+        }
     }
     return *this;
 }
@@ -57,15 +57,17 @@ bool
 Vector<void*>::reserve(int want)
 {
     if (want < 0)
-	want = (_capacity > 0 ? _capacity * 2 : 4);
+        want = (_capacity > 0 ? _capacity * 2 : 4);
     if (want <= _capacity)
-	return true;
+        return true;
 
     void **new_l = new void*[want];
     if (!new_l)
-	return false;
+        return false;
 
-    memcpy(new_l, _l, sizeof(void*) * _n);
+    if (_n) {
+        memcpy(new_l, _l, sizeof(void*) * _n);
+    }
     delete[] _l;
 
     _l = new_l;
@@ -77,21 +79,21 @@ Vector<void*>::iterator
 Vector<void*>::erase(iterator a, iterator b)
 {
     if (b > a) {
-	assert(a >= begin() && b <= end());
-	memmove(a, b, (end() - b) * sizeof(void*));
-	_n -= b - a;
-	return a;
+        assert(a >= begin() && b <= end());
+        memmove(a, b, (end() - b) * sizeof(void*));
+        _n -= b - a;
+        return a;
     } else
-	return b;
+        return b;
 }
 
 void
 Vector<void*>::resize(int nn, void *e)
 {
     if (nn <= _capacity || reserve(nn)) {
-	for (int i = _n; i < nn; i++)
-	    _l[i] = e;
-	_n = nn;
+        for (int i = _n; i < nn; i++)
+            _l[i] = e;
+        _n = nn;
     }
 }
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/main.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/main.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/main.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/main.cc	2018-02-23 12:47:54.088971828 -0500
@@ -1,6 +1,6 @@
 /* main.cc -- driver for mmafm program
  *
- * Copyright (c) 1997-2016 Eddie Kohler
+ * Copyright (c) 1997-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -322,7 +322,7 @@ main(int argc, char *argv[])
 
      case VERSION_OPT:
       printf("mmafm (LCDF typetools) %s\n", VERSION);
-      printf("Copyright (C) 1997-2016 Eddie Kohler\n\
+      printf("Copyright (C) 1997-2018 Eddie Kohler\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");
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/mmafm.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/mmafm.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/mmafm.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmafm/mmafm.1	2018-02-23 12:47:54.088971828 -0500
@@ -1,5 +1,5 @@
 .\" -*-nroff-*-
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/main.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/main.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/main.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/main.cc	2018-02-23 12:47:54.088971828 -0500
@@ -1,6 +1,6 @@
 /* main.cc -- driver for mmpfb program
  *
- * Copyright (c) 1997-2016 Eddie Kohler
+ * Copyright (c) 1997-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -355,7 +355,7 @@ main(int argc, char *argv[])
 
      case VERSION_OPT:
       printf("mmpfb (LCDF typetools) %s\n", VERSION);
-      printf("Copyright (C) 1997-2016 Eddie Kohler\n\
+      printf("Copyright (C) 1997-2018 Eddie Kohler\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");
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/mmpfb.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/mmpfb.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/mmpfb.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/mmpfb.1	2018-02-23 12:47:54.088971828 -0500
@@ -1,5 +1,5 @@
 .\" -*-nroff-*-
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/myfont.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/myfont.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/myfont.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/myfont.cc	2018-02-23 12:47:54.088971828 -0500
@@ -1,6 +1,6 @@
 /* myfont.cc -- general multiple- to single-master conversion
  *
- * Copyright (c) 1997-2016 Eddie Kohler
+ * Copyright (c) 1997-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1minimize.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1minimize.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1minimize.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1minimize.cc	2018-02-23 12:47:54.088971828 -0500
@@ -1,6 +1,6 @@
 /* t1minimize.cc -- make minimal copy of a Type 1 font
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/mmpfb/t1rewrit.cc	2018-02-23 12:47:54.088971828 -0500
@@ -1,6 +1,6 @@
 /* t1rewrit.cc -- routines for multiple- to single-master charstring conversion
  *
- * Copyright (c) 1997-2016 Eddie Kohler
+ * Copyright (c) 1997-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/NEWS.md.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/NEWS.md
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/NEWS.md.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/NEWS.md	2018-02-23 12:47:54.089971803 -0500
@@ -1,6 +1,15 @@
 LCDF Typetools NEWS
 ===================
 
+## Version 2.107 – 22.Feb.2018
+
+* Some corrections to output of `--math-spacing`.
+
+* Reduce undefined behavior.
+
+* Handle some incorrect fonts more gracefully.
+
+
 ## Version 2.106 – 21.Jun.2016
 
 * Minor updates, mostly involving licensing of Adobe code and data.
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.1	2018-02-23 12:47:54.089971803 -0500
@@ -1,5 +1,5 @@
 '\"t
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otfinfo/otfinfo.cc	2018-02-23 12:47:54.089971803 -0500
@@ -1,6 +1,6 @@
 /* otfinfo.cc -- driver for reporting information about OpenType fonts
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -528,7 +528,7 @@ do_query_unicode(const OpenType::Font& o
                 sprintf(name, "uni%04X", it->first);
             else
                 sprintf(name, "u%X", it->first);
-            if ((size_t) it->second < glyph_names.size())
+            if (it->second < glyph_names.size())
                 result_errh->message("%s %d %s\n", name, it->second, glyph_names[it->second].c_str());
             else
                 result_errh->message("%s %d\n", name, it->second);
@@ -645,7 +645,7 @@ main(int argc, char *argv[])
 
 	  case VERSION_OPT:
 	    printf("otfinfo (LCDF typetools) %s\n", VERSION);
-	    printf("Copyright (C) 2003-2016 Eddie Kohler\n\
+	    printf("Copyright (C) 2003-2018 Eddie Kohler\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");
@@ -721,5 +721,6 @@ particular purpose.\n");
 	    do_info(otf, &cerrh, result_errh);
     }
 
+    Clp_DeleteParser(clp);
     return (errh->nerrors() == 0 ? 0 : 1);
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.cc	2018-02-23 12:47:54.089971803 -0500
@@ -1,6 +1,6 @@
 /* automatic.{cc,hh} -- code for automatic mode and interfacing with kpathsea
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -39,10 +39,6 @@
 #include <algorithm>
 
 #ifdef WIN32
-#ifdef _MSC_VER
-# include <io.h>
-# include <direct.h>
-#endif
 # define mkdir(dir, access) mkdir(dir)
 # define COPY_CMD "copy"
 # define CMD_SEP "&"
@@ -93,7 +89,7 @@ static const struct {
 static String odir_kpathsea[NUMODIR];
 
 static bool writable_texdir_tried = false;
-static String writable_texdir;	// always ends with directory separator
+static String writable_texdir;  // always ends with directory separator
 static int tds_1_1 = -1;
 
 static bool mktexupd_tried = false;
@@ -112,41 +108,30 @@ look_for_writable_texdir(const char *pat
 {
     String path = kpsei_string(kpsei_path_expand(path_variable));
     while (path && !writable_texdir) {
-	const char* colon = std::find(path.begin(), path.end(), kpsei_env_sep_char);
-	String texdir = path.substring(path.begin(), colon);
-	path = path.substring(colon + 1, path.end());
-	if (access(texdir.c_str(), W_OK) >= 0)
-	    writable_texdir = texdir;
-	else if (create && errno != EACCES && mkdir(texdir.c_str(), 0777) >= 0)
-	    // create file if it doesn't exist already
-	    writable_texdir = texdir;
+        const char* colon = std::find(path.begin(), path.end(), kpsei_env_sep_char);
+        String texdir = path.substring(path.begin(), colon);
+        path = path.substring(colon + 1, path.end());
+        if (access(texdir.c_str(), W_OK) >= 0)
+            writable_texdir = texdir;
+        else if (create && errno != EACCES && mkdir(texdir.c_str(), 0777) >= 0)
+            // create file if it doesn't exist already
+            writable_texdir = texdir;
     }
     if (writable_texdir && writable_texdir.back() != '/')
-	writable_texdir += "/";
+        writable_texdir += "/";
 }
 
 static void
 find_writable_texdir(ErrorHandler *errh, const char *)
 {
-#if defined(W32TEX)
-// W32TeX does not have TEXMFVAR
-    char *p = kpsei_var_value("TEXMFVAR");
-    if (p == NULL) // W32TeX
-        look_for_writable_texdir("$TEXMFLOCAL", true);
-    else { // TeXLive
-        free (p);
-        look_for_writable_texdir("$TEXMFVAR", true);
-    }
-#else
     look_for_writable_texdir("$TEXMFVAR", true);
-#endif
     if (!writable_texdir)
-	look_for_writable_texdir("$VARTEXMF", false);
+        look_for_writable_texdir("$VARTEXMF", false);
     if (!writable_texdir)
-	look_for_writable_texdir("$TEXMF", false);
+        look_for_writable_texdir("$TEXMF", false);
     if (!writable_texdir) {
-	errh->warning("no writable directory found in $TEXMFVAR or $TEXMF");
-	errh->message("(You probably need to set your TEXMF environment variable; see\n\
+        errh->warning("no writable directory found in $TEXMFVAR or $TEXMF");
+        errh->message("(You probably need to set your TEXMF environment variable; see\n\
 the manual for more information. The current TEXMF path is\n\
 %<%s%>.)", kpsei_string(kpsei_path_expand("$TEXMF")).c_str());
     }
@@ -179,7 +164,7 @@ set_typeface(const String &s, bool overr
 {
     bool had = (bool) typeface;
     if (!had || override)
-	typeface = s;
+        typeface = s;
     return !had;
 }
 
@@ -189,91 +174,93 @@ getodir(int o, ErrorHandler *errh)
     assert(o >= 0 && o < NUMODIR);
 
     if (!odir[o] && automatic && odir_info[o].envvar)
-	odir[o] = getenv(odir_info[o].envvar);
+        odir[o] = getenv(odir_info[o].envvar);
 
 #if HAVE_KPATHSEA
     if (!odir[o] && automatic && !writable_texdir_tried)
-	find_writable_texdir(errh, odir_info[o].name);
+        find_writable_texdir(errh, odir_info[o].name);
 
     if (!odir[o] && automatic && writable_texdir) {
-	String suffix = odir_info[o].texdir;
+        String suffix = odir_info[o].texdir;
+
+        // May need to behave differently on TDS 1.1 rather than TDS 1.0.
+        if (suffix[0] == '#') {
+            // check type of TDS
+            if (tds_1_1 < 0) {
+                // using a procedure suggested by Olaf Weber
+                String encfonts = kpsei_string(kpsei_path_expand("$TEXMFMAIN/fonts/enc"));
+                if (!encfonts)
+                    encfonts = kpsei_string(kpsei_path_expand("$TEXMFDIST/fonts/enc"));
+                tds_1_1 = (encfonts != String());
+            }
+            if (tds_1_1 == 0)
+                suffix = suffix.substring(std::find(suffix.begin() + 1, suffix.end(), '#') + 1, suffix.end());
+            else
+                suffix = suffix.substring(suffix.begin() + 1, std::find(suffix.begin() + 1, suffix.end(), '#'));
+        }
+
+        String dir = writable_texdir + suffix;
+
+        if (dir.back() == '%')
+            dir = dir.substring(0, -1) + get_vendor() + "/" + get_typeface();
+        else if (dir.back() == '@')
+            dir = dir.substring(0, -1) + get_vendor();
+
+        // create parent directories as appropriate
+        int slash = writable_texdir.length() - 1;
+        while (access(dir.c_str(), F_OK) < 0 && slash < dir.length()) {
+            if ((slash = dir.find_left('/', slash + 1)) < 0)
+                slash = dir.length();
+            String subdir = dir.substring(0, slash);
+            if (access(subdir.c_str(), F_OK) < 0
+                && !no_create
+                && mkdir(subdir.c_str(), 0777) < 0)
+                goto kpathsea_done;
+        }
 
-	// May need to behave differently on TDS 1.1 rather than TDS 1.0.
-	if (suffix[0] == '#') {
-	    // check type of TDS
-	    if (tds_1_1 < 0) {
-		// using a procedure suggested by Olaf Weber
-		String encfonts = kpsei_string(kpsei_path_expand("$TEXMFMAIN/fonts/enc"));
-		if (!encfonts)
-		    encfonts = kpsei_string(kpsei_path_expand("$TEXMFDIST/fonts/enc"));
-		tds_1_1 = (encfonts != String());
-	    }
-	    if (tds_1_1 == 0)
-		suffix = suffix.substring(std::find(suffix.begin() + 1, suffix.end(), '#') + 1, suffix.end());
-	    else
-		suffix = suffix.substring(suffix.begin() + 1, std::find(suffix.begin() + 1, suffix.end(), '#'));
-	}
-
-	String dir = writable_texdir + suffix;
-
-	if (dir.back() == '%')
-	    dir = dir.substring(0, -1) + get_vendor() + "/" + get_typeface();
-	else if (dir.back() == '@')
-	    dir = dir.substring(0, -1) + get_vendor();
-
-	// create parent directories as appropriate
-	int slash = writable_texdir.length() - 1;
-	while (access(dir.c_str(), F_OK) < 0 && slash < dir.length()) {
-	    if ((slash = dir.find_left('/', slash + 1)) < 0)
-		slash = dir.length();
-	    String subdir = dir.substring(0, slash);
-	    if (access(subdir.c_str(), F_OK) < 0
-		&& !no_create
-		&& mkdir(subdir.c_str(), 0777) < 0)
-		goto kpathsea_done;
-	}
-
-	// that's our answer
-	odir[o] = dir;
-	odir_kpathsea[o] = dir;
+        // that's our answer
+        odir[o] = dir;
+        odir_kpathsea[o] = dir;
     }
   kpathsea_done:
 #endif
 
     if (!odir[o]) {
-	if (automatic) {
-	    errh->warning("%s not specified, placing %s files in %<.%>", odir_info[o].envvar, odir_info[o].name);
+        if (automatic) {
+            errh->warning("%s not specified, placing %s files in %<.%>", odir_info[o].envvar, odir_info[o].name);
 #if !HAVE_KPATHSEA
-	    static int kpathsea_warning = 0;
-	    if (++kpathsea_warning == 1)
-		errh->message("(This version of otftotfm lacks $TEXMF directory support.)");
+            static int kpathsea_warning = 0;
+            if (++kpathsea_warning == 1)
+                errh->message("(This version of otftotfm lacks $TEXMF directory support.)");
 #endif
-	}
-	odir[o] = ".";
+        }
+        odir[o] = ".";
     }
 
     while (odir[o].length() && odir[o].back() == '/')
-	odir[o] = odir[o].substring(0, -1);
+        odir[o] = odir[o].substring(0, -1);
 
     if (verbose)
-	errh->message("placing %s files in %<%s%>", odir_info[o].name, odir[o].c_str());
+        errh->message("placing %s files in %<%s%>", odir_info[o].name, odir[o].c_str());
     return odir[o];
 }
 
-bool
+void
 setodir(int o, const String &value)
 {
     assert(o >= 0 && o < NUMODIR);
-    bool had = (bool) odir[o];
     odir[o] = value;
-    return !had;
 }
 
 const char *
 odirname(int o)
 {
-    assert(o >= 0 && o < NUMODIR);
-    return odir_info[o].name;
+    if (o == NUMODIR) {
+        return "default";
+    } else {
+        assert(o >= 0 && o < NUMODIR);
+        return odir_info[o].name;
+    }
 }
 
 #if HAVE_KPATHSEA
@@ -281,9 +268,9 @@ static bool
 file_in_kpathsea_odir(int o, const String &file)
 {
     return odir_kpathsea[o]
-	&& file.length() > odir[o].length()
-	&& memcmp(file.data(), odir[o].data(), odir[o].length()) == 0
-	&& file[odir[o].length()] == '/';
+        && file.length() > odir[o].length()
+        && memcmp(file.data(), odir[o].data(), odir[o].length()) == 0
+        && file[odir[o].length()] == '/';
 }
 #endif
 
@@ -293,68 +280,64 @@ update_odir(int o, String file, ErrorHan
     assert(o >= 0 && o < NUMODIR);
 #if HAVE_KPATHSEA
     if (file.find_left('/') < 0)
-	file = odir[o] + "/" + file;
+        file = odir[o] + "/" + file;
 
     // exit if this directory was not found via kpathsea, or the file is not
     // in the kpathsea directory
     if (!file_in_kpathsea_odir(o, file))
-	return;
+        return;
 
     assert(writable_texdir && writable_texdir.length() <= odir[o].length()
-	   && memcmp(file.data(), writable_texdir.data(), writable_texdir.length()) == 0);
+           && memcmp(file.data(), writable_texdir.data(), writable_texdir.length()) == 0);
 
     // divide the filename into portions
     // file == writable_texdir + directory + file
     file = file.substring(writable_texdir.length());
     while (file && file[0] == '/')
-	file = file.substring(1);
+        file = file.substring(1);
     int last_slash = file.find_right('/');
     String directory = (last_slash >= 0 ? file.substring(0, last_slash) : String());
     file = file.substring(last_slash >= 0 ? last_slash + 1 : 0);
-    if (!file)			// no filename to update
-	return;
+    if (!file)                  // no filename to update
+        return;
 
     // return if nocreate
     if (no_create) {
-	errh->message("would update %sls-R for %s/%s", writable_texdir.c_str(), directory.c_str(), file.c_str());
-	return;
+        errh->message("would update %sls-R for %s/%s", writable_texdir.c_str(), directory.c_str(), file.c_str());
+        return;
     } else if (verbose)
-	errh->message("updating %sls-R for %s/%s", writable_texdir.c_str(), directory.c_str(), file.c_str());
+        errh->message("updating %sls-R for %s/%s", writable_texdir.c_str(), directory.c_str(), file.c_str());
 
     // try to update ls-R ourselves, rather than running mktexupd --
     // mktexupd's runtime is painful: a half second to update a file
     String ls_r = writable_texdir + "ls-R";
     bool success = false;
     if (access(ls_r.c_str(), R_OK) >= 0) // make sure it already exists
-	if (FILE *f = fopen(ls_r.c_str(), "ab")) {
-	    fprintf(f, "./%s:\n%s\n", directory.c_str(), file.c_str());
-	    success = true;
-	    fclose(f);
-	}
+        if (FILE *f = fopen(ls_r.c_str(), "a")) {
+            fprintf(f, "./%s:\n%s\n", directory.c_str(), file.c_str());
+            success = true;
+            fclose(f);
+        }
 
     // otherwise, run mktexupd
     if (!success && writable_texdir.find_left('\'') < 0 && directory.find_left('\'') < 0 && file.find_left('\'') < 0) {
-	// look for mktexupd script
-	if (!mktexupd_tried) {
-#ifdef _WIN32
-	    mktexupd = "mktexupd";
-#else
-	    mktexupd = kpsei_string(kpsei_find_file("mktexupd", KPSEI_FMT_WEB2C));
-#endif
-	    mktexupd_tried = true;
-	}
+        // look for mktexupd script
+        if (!mktexupd_tried) {
+            mktexupd = kpsei_string(kpsei_find_file("mktexupd", KPSEI_FMT_WEB2C));
+            mktexupd_tried = true;
+        }
 
-	// run script
-	if (mktexupd) {
-	    String command = mktexupd + " " + shell_quote(writable_texdir + directory) + " " + shell_quote(file);
-	    int retval = system(command.c_str());
-	    if (retval == 127)
-		errh->error("could not run %<%s%>", command.c_str());
-	    else if (retval < 0)
-		errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
-	    else if (retval != 0)
-		errh->error("%<%s%> failed", command.c_str());
-	}
+        // run script
+        if (mktexupd) {
+            String command = mktexupd + " " + shell_quote(writable_texdir + directory) + " " + shell_quote(file);
+            int retval = system(command.c_str());
+            if (retval == 127)
+                errh->error("could not run %<%s%>", command.c_str());
+            else if (retval < 0)
+                errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
+            else if (retval != 0)
+                errh->error("%<%s%> failed", command.c_str());
+        }
     }
 #else
     (void) file, (void) errh;
@@ -375,25 +358,25 @@ installed_type1(const String &otf_filena
     (void) otf_filename, (void) allow_generate, (void) errh;
 
     if (!ps_fontname)
-	return String();
+        return String();
 
 #if HAVE_KPATHSEA
 # if HAVE_AUTO_CFFTOT1
     if (!(force && allow_generate && otf_filename && otf_filename != "-" && getodir(O_TYPE1, errh))) {
 # endif
-	// look for .pfb and .pfa
-	String file, path;
-	if ((file = ps_fontname + ".pfb", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))
-	    || (file = ps_fontname + ".pfa", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))) {
-	    if (path == "./" + file || path == file) {
-		if (verbose)
-		    errh->message("ignoring Type 1 file %s found with kpathsea in %<.%>", path.c_str());
-	    } else {
-		if (verbose)
-		    errh->message("Type 1 file %s found with kpathsea at %s", file.c_str(), path.c_str());
-		return path;
-	    }
-	}
+        // look for .pfb and .pfa
+        String file, path;
+        if ((file = ps_fontname + ".pfb", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))
+            || (file = ps_fontname + ".pfa", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))) {
+            if (path == "./" + file || path == file) {
+                if (verbose)
+                    errh->message("ignoring Type 1 file %s found with kpathsea in %<.%>", path.c_str());
+            } else {
+                if (verbose)
+                    errh->message("Type 1 file %s found with kpathsea at %s", file.c_str(), path.c_str());
+                return path;
+            }
+        }
 # if HAVE_AUTO_CFFTOT1
     }
 # endif
@@ -402,21 +385,21 @@ installed_type1(const String &otf_filena
 #if HAVE_AUTO_CFFTOT1
     // if not found, and can generate on the fly, run cfftot1
     if (allow_generate && otf_filename && otf_filename != "-" && getodir(O_TYPE1, errh)) {
-	String pfb_filename = odir[O_TYPE1] + "/" + ps_fontname + ".pfb";
-	if (pfb_filename.find_left('\'') >= 0 || otf_filename.find_left('\'') >= 0)
-	    return String();
-	String command = "cfftot1 " + shell_quote(otf_filename) + " -n " + shell_quote(ps_fontname) + " " + shell_quote(pfb_filename);
-	int retval = mysystem(command.c_str(), errh);
-	if (retval == 127)
-	    errh->error("could not run %<%s%>", command.c_str());
-	else if (retval < 0)
-	    errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
-	else if (retval != 0)
-	    errh->error("%<%s%> failed", command.c_str());
-	if (retval == 0) {
-	    update_odir(O_TYPE1, pfb_filename, errh);
-	    return pfb_filename;
-	}
+        String pfb_filename = odir[O_TYPE1] + "/" + ps_fontname + ".pfb";
+        if (pfb_filename.find_left('\'') >= 0 || otf_filename.find_left('\'') >= 0)
+            return String();
+        String command = "cfftot1 " + shell_quote(otf_filename) + " -n " + shell_quote(ps_fontname) + " " + shell_quote(pfb_filename);
+        int retval = mysystem(command.c_str(), errh);
+        if (retval == 127)
+            errh->error("could not run %<%s%>", command.c_str());
+        else if (retval < 0)
+            errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
+        else if (retval != 0)
+            errh->error("%<%s%> failed", command.c_str());
+        if (retval == 0) {
+            update_odir(O_TYPE1, pfb_filename, errh);
+            return pfb_filename;
+        }
     }
 #endif
 
@@ -429,9 +412,9 @@ installed_type1_dotlessj(const String &o
     (void) otf_filename, (void) allow_generate, (void) errh;
 
     if (!ps_fontname)
-	return String();
+        return String();
     if (verbose)
-	errh->message("searching for dotless-j font for %s", ps_fontname.c_str());
+        errh->message("searching for dotless-j font for %s", ps_fontname.c_str());
 
     String j_ps_fontname = ps_fontname + "LCDFJ";
 
@@ -439,20 +422,20 @@ installed_type1_dotlessj(const String &o
 # if HAVE_AUTO_T1DOTLESSJ
     if (!(force && allow_generate && getodir(O_TYPE1, errh))) {
 # endif
-	// look for existing .pfb or .pfa
-	String file, path;
-	if ((file = j_ps_fontname + ".pfb", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))
-	    || (file = j_ps_fontname + ".pfa", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))) {
-	    // ignore versions in the current directory
-	    if (path == "./" + file || path == file) {
-		if (verbose)
-		    errh->message("ignoring Type 1 file %s found with kpathsea in %<.%>", path.c_str());
-	    } else {
-		if (verbose)
-		    errh->message("Type 1 file %s found with kpathsea at %s", file.c_str(), path.c_str());
-		return path;
-	    }
-	}
+        // look for existing .pfb or .pfa
+        String file, path;
+        if ((file = j_ps_fontname + ".pfb", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))
+            || (file = j_ps_fontname + ".pfa", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))) {
+            // ignore versions in the current directory
+            if (path == "./" + file || path == file) {
+                if (verbose)
+                    errh->message("ignoring Type 1 file %s found with kpathsea in %<.%>", path.c_str());
+            } else {
+                if (verbose)
+                    errh->message("Type 1 file %s found with kpathsea at %s", file.c_str(), path.c_str());
+                return path;
+            }
+        }
 # if HAVE_AUTO_T1DOTLESSJ
     }
 # endif
@@ -461,26 +444,26 @@ installed_type1_dotlessj(const String &o
 #if HAVE_AUTO_T1DOTLESSJ
     // if not found, and can generate on the fly, try running t1dotlessj
     if (allow_generate && getodir(O_TYPE1, errh)) {
-	if (String base_filename = installed_type1(otf_filename, ps_fontname, allow_generate, errh)) {
-	    String pfb_filename = odir[O_TYPE1] + "/" + j_ps_fontname + ".pfb";
-	    if (pfb_filename.find_left('\'') >= 0 || base_filename.find_left('\'') >= 0)
-		return String();
-	    String command = "t1dotlessj " + shell_quote(base_filename) + " -n " + shell_quote(j_ps_fontname) + " " + shell_quote(pfb_filename);
-	    int retval = mysystem(command.c_str(), errh);
-	    if (retval == 127)
-		errh->warning("could not run %<%s%>", command.c_str());
-	    else if (retval < 0)
-		errh->warning("could not run %<%s%>: %s", command.c_str(), strerror(errno));
-	    else if (WEXITSTATUS(retval) == T1DOTLESSJ_EXIT_J_NODOT)
-		return String("\0", 1);
-	    else if (retval != 0)
-		errh->warning("%<%s%> failed (%d)", command.c_str(), retval);
-	    if (retval == 0) {
-		update_odir(O_TYPE1, pfb_filename, errh);
-		return pfb_filename;
-	    } else
-		errh->warning("output font will not contain a dotless-j character");
-	}
+        if (String base_filename = installed_type1(otf_filename, ps_fontname, allow_generate, errh)) {
+            String pfb_filename = odir[O_TYPE1] + "/" + j_ps_fontname + ".pfb";
+            if (pfb_filename.find_left('\'') >= 0 || base_filename.find_left('\'') >= 0)
+                return String();
+            String command = "t1dotlessj " + shell_quote(base_filename) + " -n " + shell_quote(j_ps_fontname) + " " + shell_quote(pfb_filename);
+            int retval = mysystem(command.c_str(), errh);
+            if (retval == 127)
+                errh->warning("could not run %<%s%>", command.c_str());
+            else if (retval < 0)
+                errh->warning("could not run %<%s%>: %s", command.c_str(), strerror(errno));
+            else if (WEXITSTATUS(retval) == T1DOTLESSJ_EXIT_J_NODOT)
+                return String("\0", 1);
+            else if (retval != 0)
+                errh->warning("%<%s%> failed (%d)", command.c_str(), retval);
+            if (retval == 0) {
+                update_odir(O_TYPE1, pfb_filename, errh);
+                return pfb_filename;
+            } else
+                errh->warning("output font will not contain a dotless-j character");
+        }
     }
 #endif
 
@@ -494,45 +477,45 @@ installed_truetype(const String &ttf_fil
 
 #if HAVE_KPATHSEA
     if (!(force && allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TRUETYPE, errh))) {
-	if (String path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TRUETYPE))) {
-	    if (path == "./" + file || path == file) {
-		if (verbose)
-		    errh->message("ignoring TrueType file %s found with kpathsea in %<.%>", path.c_str());
-	    } else {
-		if (verbose)
-		    errh->message("TrueType file %s found with kpathsea at %s", file.c_str(), path.c_str());
-		return path;
-	    }
-	}
+        if (String path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TRUETYPE))) {
+            if (path == "./" + file || path == file) {
+                if (verbose)
+                    errh->message("ignoring TrueType file %s found with kpathsea in %<.%>", path.c_str());
+            } else {
+                if (verbose)
+                    errh->message("TrueType file %s found with kpathsea at %s", file.c_str(), path.c_str());
+                return path;
+            }
+        }
     }
 #endif
 
     // perhaps generate type 42 in the future, for now just copy
     if (allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TRUETYPE, errh)) {
-	String installed_ttf_filename = odir[O_TRUETYPE] + "/" + file;
-	if (installed_ttf_filename.find_left('\'') >= 0 || installed_ttf_filename.find_left('\"') >= 0)
-	    return String();
-
-	int retval;
-	if (!same_filename(ttf_filename, installed_ttf_filename)) {
-	    String command = COPY_CMD " " + shell_quote(ttf_filename) + " " + shell_quote(installed_ttf_filename);
-	    retval = mysystem(command.c_str(), errh);
-	    if (retval == 127)
-		errh->error("could not run %<%s%>", command.c_str());
-	    else if (retval < 0)
-		errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
-	    else if (retval != 0)
-		errh->error("%<%s%> failed", command.c_str());
-	} else {
-	    if (verbose)
-		errh->message("TrueType file %s already located in output directory", installed_ttf_filename.c_str());
-	    retval = 0;
-	}
-
-	if (retval == 0) {
-	    update_odir(O_TRUETYPE, installed_ttf_filename, errh);
-	    return installed_ttf_filename;
-	}
+        String installed_ttf_filename = odir[O_TRUETYPE] + "/" + file;
+        if (installed_ttf_filename.find_left('\'') >= 0 || installed_ttf_filename.find_left('\"') >= 0)
+            return String();
+
+        int retval;
+        if (!same_filename(ttf_filename, installed_ttf_filename)) {
+            String command = COPY_CMD " " + shell_quote(ttf_filename) + " " + shell_quote(installed_ttf_filename);
+            retval = mysystem(command.c_str(), errh);
+            if (retval == 127)
+                errh->error("could not run %<%s%>", command.c_str());
+            else if (retval < 0)
+                errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
+            else if (retval != 0)
+                errh->error("%<%s%> failed", command.c_str());
+        } else {
+            if (verbose)
+                errh->message("TrueType file %s already located in output directory", installed_ttf_filename.c_str());
+            retval = 0;
+        }
+
+        if (retval == 0) {
+            update_odir(O_TRUETYPE, installed_ttf_filename, errh);
+            return installed_ttf_filename;
+        }
     }
 
     return String();
@@ -544,24 +527,24 @@ installed_type42(const String &ttf_filen
     (void) allow_generate, (void) ttf_filename, (void) errh;
 
     if (!ps_fontname)
-	return String();
+        return String();
 
 #if HAVE_KPATHSEA
 # if HAVE_AUTO_TTFTOTYPE42
     if (!(force && allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TYPE42, errh))) {
 # endif
-	// look for .pfb and .pfa
-	String file, path;
-	if ((file = ps_fontname + ".t42", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE42)))) {
-	    if (path == "./" + file || path == file) {
-		if (verbose)
-		    errh->message("ignoring Type 42 file %s found with kpathsea in %<.%>", path.c_str());
-	    } else {
-		if (verbose)
-		    errh->message("Type 42 file %s found with kpathsea at %s", file.c_str(), path.c_str());
-		return path;
-	    }
-	}
+        // look for .pfb and .pfa
+        String file, path;
+        if ((file = ps_fontname + ".t42", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE42)))) {
+            if (path == "./" + file || path == file) {
+                if (verbose)
+                    errh->message("ignoring Type 42 file %s found with kpathsea in %<.%>", path.c_str());
+            } else {
+                if (verbose)
+                    errh->message("Type 42 file %s found with kpathsea at %s", file.c_str(), path.c_str());
+                return path;
+            }
+        }
 # if HAVE_AUTO_TTFTOTYPE42
     }
 # endif
@@ -570,21 +553,21 @@ installed_type42(const String &ttf_filen
 #if HAVE_AUTO_TTFTOTYPE42
     // if not found, and can generate on the fly, run ttftotype42
     if (allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TYPE42, errh)) {
-	String t42_filename = odir[O_TYPE42] + "/" + ps_fontname + ".t42";
-	if (t42_filename.find_left('\'') >= 0 || ttf_filename.find_left('\'') >= 0)
-	    return String();
-	String command = "ttftotype42 " + shell_quote(ttf_filename) + " " + shell_quote(t42_filename);
-	int retval = mysystem(command.c_str(), errh);
-	if (retval == 127)
-	    errh->error("could not run %<%s%>", command.c_str());
-	else if (retval < 0)
-	    errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
-	else if (retval != 0)
-	    errh->error("%<%s%> failed", command.c_str());
-	if (retval == 0) {
-	    update_odir(O_TYPE42, t42_filename, errh);
-	    return t42_filename;
-	}
+        String t42_filename = odir[O_TYPE42] + "/" + ps_fontname + ".t42";
+        if (t42_filename.find_left('\'') >= 0 || ttf_filename.find_left('\'') >= 0)
+            return String();
+        String command = "ttftotype42 " + shell_quote(ttf_filename) + " " + shell_quote(t42_filename);
+        int retval = mysystem(command.c_str(), errh);
+        if (retval == 127)
+            errh->error("could not run %<%s%>", command.c_str());
+        else if (retval < 0)
+            errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
+        else if (retval != 0)
+            errh->error("%<%s%> failed", command.c_str());
+        if (retval == 0) {
+            update_odir(O_TYPE42, t42_filename, errh);
+            return t42_filename;
+        }
     }
 #endif
 
@@ -596,94 +579,94 @@ update_autofont_map(const String &fontna
 {
 #if HAVE_KPATHSEA
     if (automatic && !map_file && getodir(O_MAP, errh))
-	map_file = odir[O_MAP] + "/" + get_vendor() + ".map";
+        map_file = odir[O_MAP] + "/" + get_vendor() + ".map";
 #endif
 
     if (map_file == "" || map_file == "-")
-	fputs(mapline.c_str(), stdout);
+        fputs(mapline.c_str(), stdout);
     else {
-	// report no_create/verbose
-	if (no_create) {
-	    errh->message("would update %s for %s", map_file.c_str(), String(fontname).c_str());
-	    return 0;
-	} else if (verbose)
-	    errh->message("updating %s for %s", map_file.c_str(), String(fontname).c_str());
-
-	int fd = open(map_file.c_str(), O_RDWR | O_CREAT, 0666);
-	if (fd < 0)
-	    return errh->lerror(map_file, "%s", strerror(errno));
-	FILE *f = fdopen(fd, "r+");
-	// NB: also change encoding logic if you change this code
+        // report no_create/verbose
+        if (no_create) {
+            errh->message("would update %s for %s", map_file.c_str(), String(fontname).c_str());
+            return 0;
+        } else if (verbose)
+            errh->message("updating %s for %s", map_file.c_str(), String(fontname).c_str());
+
+        int fd = open(map_file.c_str(), O_RDWR | O_CREAT, 0666);
+        if (fd < 0)
+            return errh->lerror(map_file, "%s", strerror(errno));
+        FILE *f = fdopen(fd, "r+");
+        // NB: also change encoding logic if you change this code
 
 #if defined(F_SETLKW) && defined(HAVE_FTRUNCATE)
-	{
-	    struct flock lock;
-	    lock.l_type = F_WRLCK;
-	    lock.l_whence = SEEK_SET;
-	    lock.l_start = 0;
-	    lock.l_len = 0;
-	    int result;
-	    while ((result = fcntl(fd, F_SETLKW, &lock)) < 0 && errno == EINTR)
-		/* try again */;
-	    if (result < 0) {
-		result = errno;
-		fclose(f);
-		return errh->error("locking %s: %s", map_file.c_str(), strerror(result));
-	    }
-	}
-#endif
-
-	// read old data from map file
-	StringAccum sa;
-	int amt;
-	do {
-	    if (char *x = sa.reserve(8192)) {
-		amt = fread(x, 1, 8192, f);
-		sa.adjust_length(amt);
-	    } else
-		amt = 0;
-	} while (amt != 0);
-	if (!feof(f))
-	    return errh->error("%s: %s", map_file.c_str(), strerror(errno));
-	String text = sa.take_string();
-
-	// add comment if necessary
-	bool created = (!text);
-	if (created)
-	    text = "% Automatically maintained by otftotfm or other programs. Do not edit.\n\n";
-	if (text.back() != '\n')
-	    text += "\n";
-
-	// append old encodings
-	int fl = 0;
-	int nl = text.find_left('\n') + 1;
-	bool changed = created;
-	while (fl < text.length()) {
-	    if (fl + fontname.length() + 1 < nl
-		&& memcmp(text.data() + fl, fontname.data(), fontname.length()) == 0
-		&& text[fl + fontname.length()] == ' ') {
-		// found the old name
-		if (text.substring(fl, nl - fl) == mapline) {
-		    // duplicate of old name, don't change it
-		    fclose(f);
-		    if (verbose)
-			errh->message("%s unchanged", map_file.c_str());
-		    return 0;
-		} else {
-		    text = text.substring(0, fl) + text.substring(nl);
-		    nl = fl;
-		    changed = true;
-		}
-	    }
-	    fl = nl;
-	    nl = text.find_left('\n', fl) + 1;
-	}
+        {
+            struct flock lock;
+            lock.l_type = F_WRLCK;
+            lock.l_whence = SEEK_SET;
+            lock.l_start = 0;
+            lock.l_len = 0;
+            int result;
+            while ((result = fcntl(fd, F_SETLKW, &lock)) < 0 && errno == EINTR)
+                /* try again */;
+            if (result < 0) {
+                result = errno;
+                fclose(f);
+                return errh->error("locking %s: %s", map_file.c_str(), strerror(result));
+            }
+        }
+#endif
+
+        // read old data from map file
+        StringAccum sa;
+        int amt;
+        do {
+            if (char *x = sa.reserve(8192)) {
+                amt = fread(x, 1, 8192, f);
+                sa.adjust_length(amt);
+            } else
+                amt = 0;
+        } while (amt != 0);
+        if (!feof(f))
+            return errh->error("%s: %s", map_file.c_str(), strerror(errno));
+        String text = sa.take_string();
+
+        // add comment if necessary
+        bool created = (!text);
+        if (created)
+            text = "% Automatically maintained by otftotfm or other programs. Do not edit.\n\n";
+        if (text.back() != '\n')
+            text += "\n";
+
+        // append old encodings
+        int fl = 0;
+        int nl = text.find_left('\n') + 1;
+        bool changed = created;
+        while (fl < text.length()) {
+            if (fl + fontname.length() + 1 < nl
+                && memcmp(text.data() + fl, fontname.data(), fontname.length()) == 0
+                && text[fl + fontname.length()] == ' ') {
+                // found the old name
+                if (text.substring(fl, nl - fl) == mapline) {
+                    // duplicate of old name, don't change it
+                    fclose(f);
+                    if (verbose)
+                        errh->message("%s unchanged", map_file.c_str());
+                    return 0;
+                } else {
+                    text = text.substring(0, fl) + text.substring(nl);
+                    nl = fl;
+                    changed = true;
+                }
+            }
+            fl = nl;
+            nl = text.find_left('\n', fl) + 1;
+        }
 
-	if (!mapline && !changed) {
+        if (!mapline && !changed) {
             // special case: empty mapline, unchanged file
-	    if (verbose)
-		errh->message("%s unchanged", map_file.c_str());
-	} else {
+            if (verbose)
+                errh->message("%s unchanged", map_file.c_str());
+        } else {
             // add our text
             text += mapline;
 
@@ -694,7 +677,7 @@ update_autofont_map(const String &fontna
 #endif
             {
                 fclose(f);
-                f = fopen(map_file.c_str(), "wb");
+                f = fopen(map_file.c_str(), "w");
                 fd = fileno(f);
             }
 
@@ -702,87 +685,78 @@ update_autofont_map(const String &fontna
             ignore_result(fwrite(text.data(), 1, text.length(), f));
         }
 
-	fclose(f);
+        fclose(f);
 
-	// inform about the new file if necessary
-	if (created)
-	    update_odir(O_MAP, map_file, errh);
+        // inform about the new file if necessary
+        if (created)
+            update_odir(O_MAP, map_file, errh);
 
 #if HAVE_KPATHSEA && !WIN32
-	// run 'updmap' if present
-	String updmap_dir, updmap_file;
-	if (automatic && (output_flags & G_UPDMAP))
-	    updmap_dir = getodir(O_MAP_PARENT, errh);
-	if (updmap_dir && (updmap_file = updmap_dir + "/updmap")
-	    && access(updmap_file.c_str(), X_OK) >= 0) {
-	    // want to run 'updmap' from its directory, can't use system()
-	    if (verbose)
-		errh->message("running %s", updmap_file.c_str());
-
-	    pid_t child = fork();
-	    if (child < 0)
-		errh->fatal("%s during fork", strerror(errno));
-	    else if (child == 0) {
-		// change to updmap directory, run it
-		if (chdir(updmap_dir.c_str()) < 0)
-		    errh->fatal("%s: %s during chdir", updmap_dir.c_str(), strerror(errno));
-		if (execl("./updmap", updmap_file.c_str(), (const char*) 0) < 0)
-		    errh->fatal("%s: %s during exec", updmap_file.c_str(), strerror(errno));
-		exit(1);	// should never get here
-	    }
+        // run 'updmap' if present
+        String updmap_dir, updmap_file;
+        if (automatic && (output_flags & G_UPDMAP))
+            updmap_dir = getodir(O_MAP_PARENT, errh);
+        if (updmap_dir && (updmap_file = updmap_dir + "/updmap")
+            && access(updmap_file.c_str(), X_OK) >= 0) {
+            // want to run 'updmap' from its directory, can't use system()
+            if (verbose)
+                errh->message("running %s", updmap_file.c_str());
+
+            pid_t child = fork();
+            if (child < 0)
+                errh->fatal("%s during fork", strerror(errno));
+            else if (child == 0) {
+                // change to updmap directory, run it
+                if (chdir(updmap_dir.c_str()) < 0)
+                    errh->fatal("%s: %s during chdir", updmap_dir.c_str(), strerror(errno));
+                if (execl("./updmap", updmap_file.c_str(), (const char*) 0) < 0)
+                    errh->fatal("%s: %s during exec", updmap_file.c_str(), strerror(errno));
+                exit(1);        // should never get here
+            }
 
 # if HAVE_WAITPID
-	    // wait for updmap to finish
-	    int status;
-	    while (1) {
-		pid_t answer = waitpid(child, &status, 0);
-		if (answer >= 0)
-		    break;
-		else if (errno != EINTR)
-		    errh->fatal("%s during wait", strerror(errno));
-	    }
-	    if (!WIFEXITED(status))
-		errh->warning("%s exited abnormally", updmap_file.c_str());
-	    else if (WEXITSTATUS(status) != 0)
-		errh->warning("%s exited with status %d", updmap_file.c_str(), WEXITSTATUS(status));
+            // wait for updmap to finish
+            int status;
+            while (1) {
+                pid_t answer = waitpid(child, &status, 0);
+                if (answer >= 0)
+                    break;
+                else if (errno != EINTR)
+                    errh->fatal("%s during wait", strerror(errno));
+            }
+            if (!WIFEXITED(status))
+                errh->warning("%s exited abnormally", updmap_file.c_str());
+            else if (WEXITSTATUS(status) != 0)
+                errh->warning("%s exited with status %d", updmap_file.c_str(), WEXITSTATUS(status));
 # else
 #  error "need waitpid() support: report this bug to the maintainer"
 # endif
-	    goto ran_updmap;
-	}
+            goto ran_updmap;
+        }
 
 # if HAVE_AUTO_UPDMAP
-	// run system updmap
-	if (output_flags & G_UPDMAP) {
-	    String filename = map_file;
-	    int slash = filename.find_right('/');
-	    if (slash >= 0)
-		filename = filename.substring(slash + 1);
+        // run system updmap
+        if (output_flags & G_UPDMAP) {
+            String filename = map_file;
+            int slash = filename.find_right('/');
+            if (slash >= 0)
+                filename = filename.substring(slash + 1);
             String redirect = verbose ? " 1>&2" : " >" DEV_NULL " 2>&1";
-#if defined(W32TEX)
-// jtex_filetype is defined only in W32TeX
-	    char *p = kpsei_var_value("jtex_filetype");
-	    if (p != NULL) { // W32TeX
-		free(p);
-		String option = "--add ";
-	    } else // TeXLive
-#endif
-	    String option = "--enable Map ";
-	    String command = "updmap --nomkmap " + option  + shell_quote(filename) + redirect
+            String command = "updmap --nomkmap --enable Map " + shell_quote(filename) + redirect
                 + CMD_SEP " updmap" + redirect;
-	    int retval = mysystem(command.c_str(), errh);
-	    if (retval == 127)
-		errh->warning("could not run %<%s%>", command.c_str());
-	    else if (retval < 0)
-		errh->warning("could not run %<%s%>: %s", command.c_str(), strerror(errno));
-	    else if (retval != 0)
-		errh->warning("%<%s%> exited with status %d;\nrun it manually to check for errors", command.c_str(), WEXITSTATUS(retval));
-	    goto ran_updmap;
-	}
+            int retval = mysystem(command.c_str(), errh);
+            if (retval == 127)
+                errh->warning("could not run %<%s%>", command.c_str());
+            else if (retval < 0)
+                errh->warning("could not run %<%s%>: %s", command.c_str(), strerror(errno));
+            else if (retval != 0)
+                errh->warning("%<%s%> exited with status %d;\nrun it manually to check for errors", command.c_str(), WEXITSTATUS(retval));
+            goto ran_updmap;
+        }
 # endif
 
-	if (verbose)
-	    errh->message("not running updmap");
+        if (verbose)
+            errh->message("not running updmap");
 
       ran_updmap: ;
 #endif
@@ -795,27 +769,27 @@ String
 locate_encoding(String encfile, ErrorHandler *errh, bool literal)
 {
     if (!encfile || encfile == "-")
-	return encfile;
+        return encfile;
 
     if (!literal) {
-	int slash = encfile.find_right('/');
-	int dot = encfile.find_left('.', slash >= 0 ? slash : 0);
-	if (dot < 0)
-	    if (String file = locate_encoding(encfile + ".enc", errh, true))
-		return file;
+        int slash = encfile.find_right('/');
+        int dot = encfile.find_left('.', slash >= 0 ? slash : 0);
+        if (dot < 0)
+            if (String file = locate_encoding(encfile + ".enc", errh, true))
+                return file;
     }
 
 #if HAVE_KPATHSEA
     if (String file = kpsei_string(kpsei_find_file(encfile.c_str(), KPSEI_FMT_ENCODING))) {
-	if (verbose)
-	    errh->message("encoding file %s found with kpathsea at %s", encfile.c_str(), file.c_str());
-	return file;
+        if (verbose)
+            errh->message("encoding file %s found with kpathsea at %s", encfile.c_str(), file.c_str());
+        return file;
     } else if (verbose)
-	errh->message("encoding file %s not found with kpathsea", encfile.c_str());
+        errh->message("encoding file %s not found with kpathsea", encfile.c_str());
 #endif
 
     if (access(encfile.c_str(), R_OK) >= 0)
-	return encfile;
+        return encfile;
     else
-	return String();
+        return String();
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/automatic.hh	2018-02-23 12:47:54.090971778 -0500
@@ -3,13 +3,15 @@
 #include <lcdf/string.hh>
 class ErrorHandler;
 
-enum { O_ENCODING = 0, O_TFM, O_PL, O_VF, O_VPL, O_TYPE1, O_MAP, O_MAP_PARENT,
-       O_TRUETYPE, O_OPENTYPE, O_TYPE42, NUMODIR };
+enum {
+    O_ENCODING = 0, O_TFM, O_PL, O_VF, O_VPL, O_TYPE1, O_MAP, O_MAP_PARENT,
+    O_TRUETYPE, O_OPENTYPE, O_TYPE42, NUMODIR
+};
 
 extern bool automatic;
 extern bool no_create;
 String getodir(int o, ErrorHandler *);
-bool setodir(int o, const String &);
+void setodir(int o, const String &);
 bool set_vendor(const String &);
 bool set_typeface(const String &, bool override);
 bool set_map_file(const String &);
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.cc	2018-02-23 12:47:54.090971778 -0500
@@ -1,6 +1,6 @@
 /* dvipsencoding.{cc,hh} -- store a DVIPS encoding
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -35,90 +35,90 @@ static Vector<uint32_t> glyphmap;
 static PermString::Initializer perm_initializer;
 PermString DvipsEncoding::dot_notdef(".notdef");
 
-#define NEXT_GLYPH_NAME(gn)	("/" + (gn))
+#define NEXT_GLYPH_NAME(gn)     ("/" + (gn))
 
 void
 DvipsEncoding::add_glyphlist(String text)
 {
     const char *s = text.begin(), *end = text.end();
     while (s != end) {
-	// move to first nonblank
-	while (s != end && isspace((unsigned char) *s))
-	    ++s;
-	// ignore comments
-	if (s != end && *s == '#') {
-	skip_to_end_of_line:
-	    while (s != end && *s != '\n' && *s != '\r')
-		++s;
-	    continue;
-	}
-	// parse glyph name
-	const char *name_start = s;
-	while (s != end && !isspace((unsigned char) *s) && *s != ';')
-	    ++s;
-	if (s == name_start)
-	    goto skip_to_end_of_line;
-	String glyph_name = text.substring(name_start, s).compact();
-	int map_pos = glyphmap.size();
-	// parse Unicodes
-	while (1) {
-	    while (s != end && (*s == ' ' || *s == '\t'))
-		++s;
-	    if (s == end || *s == '\n' || *s == '\r' || *s == '#'
-		|| (map_pos == glyphmap.size() && *s != ';' && *s != ','))
-		break;
-	    if (*s == ';' || *s == ',') {
-		++s;
-		while (s != end && (*s == ' ' || *s == '\t'))
-		    ++s;
-		if (s == end || !isxdigit((unsigned char) *s))
-		    goto skip_to_end_of_line;
-		if (map_pos != glyphmap.size())
-		    glyphmap.push_back(GLYPHLIST_ALTERNATIVE);
-	    }
-	    uint32_t u = 0;
-	    while (s != end && isxdigit((unsigned char) *s)) {
-		if (*s >= '0' && *s <= '9')
-		    u = (u << 4) + *s - '0';
-		else if (*s >= 'A' && *s <= 'F')
-		    u = (u << 4) + *s - 'A' + 10;
-		else
-		    u = (u << 4) + *s - 'a' + 10;
-		++s;
-	    }
-	    if (u == 0 || u > 0x10FFFF)
-		goto skip_to_end_of_line;
-	    glyphmap.push_back(u);
-	    if (s != end && !isspace((unsigned char) *s) && *s != ',' && *s != ';')
-		break;
-	}
-	// store result
-	if (map_pos == glyphmap.size() - 1) {
-	    glyphlist.insert(glyph_name, glyphmap.back());
-	    glyphmap.pop_back();
-	} else {
-	    glyphlist.insert(glyph_name, map_pos | GLYPHLIST_USEMAP);
-	    glyphmap.push_back(0);
-	}
-	goto skip_to_end_of_line;
+        // move to first nonblank
+        while (s != end && isspace((unsigned char) *s))
+            ++s;
+        // ignore comments
+        if (s != end && *s == '#') {
+        skip_to_end_of_line:
+            while (s != end && *s != '\n' && *s != '\r')
+                ++s;
+            continue;
+        }
+        // parse glyph name
+        const char *name_start = s;
+        while (s != end && !isspace((unsigned char) *s) && *s != ';')
+            ++s;
+        if (s == name_start)
+            goto skip_to_end_of_line;
+        String glyph_name = text.substring(name_start, s).compact();
+        int map_pos = glyphmap.size();
+        // parse Unicodes
+        while (1) {
+            while (s != end && (*s == ' ' || *s == '\t'))
+                ++s;
+            if (s == end || *s == '\n' || *s == '\r' || *s == '#'
+                || (map_pos == glyphmap.size() && *s != ';' && *s != ','))
+                break;
+            if (*s == ';' || *s == ',') {
+                ++s;
+                while (s != end && (*s == ' ' || *s == '\t'))
+                    ++s;
+                if (s == end || !isxdigit((unsigned char) *s))
+                    goto skip_to_end_of_line;
+                if (map_pos != glyphmap.size())
+                    glyphmap.push_back(GLYPHLIST_ALTERNATIVE);
+            }
+            uint32_t u = 0;
+            while (s != end && isxdigit((unsigned char) *s)) {
+                if (*s >= '0' && *s <= '9')
+                    u = (u << 4) + *s - '0';
+                else if (*s >= 'A' && *s <= 'F')
+                    u = (u << 4) + *s - 'A' + 10;
+                else
+                    u = (u << 4) + *s - 'a' + 10;
+                ++s;
+            }
+            if (u == 0 || u > 0x10FFFF)
+                goto skip_to_end_of_line;
+            glyphmap.push_back(u);
+            if (s != end && !isspace((unsigned char) *s) && *s != ',' && *s != ';')
+                break;
+        }
+        // store result
+        if (map_pos == glyphmap.size() - 1) {
+            glyphlist.insert(glyph_name, glyphmap.back());
+            glyphmap.pop_back();
+        } else {
+            glyphlist.insert(glyph_name, map_pos | GLYPHLIST_USEMAP);
+            glyphmap.push_back(0);
+        }
+        goto skip_to_end_of_line;
     }
 }
 
 static void
 unicode_add_suffix(Vector<uint32_t> &prefix,
-		   int prefix_starting_from,
-		   const Vector<uint32_t> &suffix)
+                   int prefix_starting_from,
+                   const Vector<uint32_t> &suffix)
 {
     int prefix_size = prefix.size();
     for (Vector<uint32_t>::const_iterator it = suffix.begin();
-	 it != suffix.end() && *it != 0;
-	 ++it)
-	if (*it == GLYPHLIST_ALTERNATIVE) {
-	    prefix.push_back(*it);
-	    for (int i = prefix_starting_from; i < prefix_size; ++i)
-		prefix.push_back(prefix[i]);
-	} else
-	    prefix.push_back(*it);
+         it != suffix.end() && *it != 0;
+         ++it)
+        if (*it == GLYPHLIST_ALTERNATIVE) {
+            prefix.push_back(*it);
+            for (int i = prefix_starting_from; i < prefix_size; ++i)
+                prefix.push_back(prefix[i]);
+        } else
+            prefix.push_back(*it);
 }
 
 bool
@@ -129,7 +129,7 @@ DvipsEncoding::glyphname_unicode(String
     // drop all characters to the right of the first dot
     String::iterator dot = std::find(gn.begin(), gn.end(), '.');
     if (dot > gn.begin() && dot < gn.end())
-	gn = gn.substring(gn.begin(), dot);
+        gn = gn.substring(gn.begin(), dot);
 
     // map the first component, handle later components recursively
     String::iterator underscore = std::find(gn.begin(), gn.end(), '_');
@@ -137,47 +137,47 @@ DvipsEncoding::glyphname_unicode(String
     int prefix_start = 0;
     Vector<uint32_t> suffix;
     if (String gn_suffix = gn.substring(underscore + 1, gn.end())) {
-	if (!glyphname_unicode(gn_suffix, suffix))
-	    return false;
+        if (!glyphname_unicode(gn_suffix, suffix))
+            return false;
     }
 
     // check glyphlist
     int value = glyphlist[component];
     uint32_t uval;
     if (value >= 0 && !(value & GLYPHLIST_USEMAP))
-	unis.push_back(value);
+        unis.push_back(value);
     else if (value >= 0) {
-	for (int i = (value & ~GLYPHLIST_USEMAP);
-	     glyphmap[i];
-	     ++i)
-	    if (glyphmap[i] == GLYPHLIST_ALTERNATIVE) {
-		unicode_add_suffix(unis, prefix_start, suffix);
-		unis.push_back(GLYPHLIST_ALTERNATIVE);
-		prefix_start = unis.size();
-	    } else
-		unis.push_back(glyphmap[i]);
+        for (int i = (value & ~GLYPHLIST_USEMAP);
+             glyphmap[i];
+             ++i)
+            if (glyphmap[i] == GLYPHLIST_ALTERNATIVE) {
+                unicode_add_suffix(unis, prefix_start, suffix);
+                unis.push_back(GLYPHLIST_ALTERNATIVE);
+                prefix_start = unis.size();
+            } else
+                unis.push_back(glyphmap[i]);
     } else if (component.length() >= 7
-	       && (component.length() % 4) == 3
-	       && (memcmp(component.data(), "uni", 3) == 0
-		   // 16.Aug.2008: Some texnansx.enc have incorrect "Uni"
-		   // prefix, but we might as well understand it.
-		   || memcmp(component.data(), "Uni", 3) == 0)) {
-	for (const char *s = component.begin() + 3;
-	     s < component.end();
-	     s += 4)
-	    if (parse_unicode_number(s, s + 4, -1, uval))
-		unis.push_back(uval);
-	    else {
-		unis.resize(unis_first_size);
-		return false;
-	    }
+               && (component.length() % 4) == 3
+               && (memcmp(component.data(), "uni", 3) == 0
+                   // 16.Aug.2008: Some texnansx.enc have incorrect "Uni"
+                   // prefix, but we might as well understand it.
+                   || memcmp(component.data(), "Uni", 3) == 0)) {
+        for (const char *s = component.begin() + 3;
+             s < component.end();
+             s += 4)
+            if (parse_unicode_number(s, s + 4, -1, uval))
+                unis.push_back(uval);
+            else {
+                unis.resize(unis_first_size);
+                return false;
+            }
     } else if (component.length() >= 5
-	       && component.length() <= 7
-	       && component[0] == 'u'
-	       && parse_unicode_number(component.begin() + 1, component.end(), -1, uval))
-	unis.push_back(uval);
+               && component.length() <= 7
+               && component[0] == 'u'
+               && parse_unicode_number(component.begin() + 1, component.end(), -1, uval))
+        unis.push_back(uval);
     else
-	return false;
+        return false;
 
     unicode_add_suffix(unis, prefix_start, suffix);
     return true;
@@ -194,7 +194,7 @@ void
 DvipsEncoding::encode(int e, PermString what)
 {
     if (e >= _e.size())
-	_e.resize(e + 1, dot_notdef);
+        _e.resize(e + 1, dot_notdef);
     _e[e] = what;
 }
 
@@ -203,21 +203,21 @@ DvipsEncoding::encoding_of(PermString wh
 {
     int slot = -1;
     for (int i = 0; i < _e.size(); i++)
-	if (_e[i] == what) {
-	    slot = i;
-	    goto use_slot;
-	} else if (!_e[i] || _e[i] == dot_notdef)
-	    slot = i;
+        if (_e[i] == what) {
+            slot = i;
+            goto use_slot;
+        } else if (!_e[i] || _e[i] == dot_notdef)
+            slot = i;
     if (what == "||")
-	return _boundary_char;
+        return _boundary_char;
     else if (!encoding_required || slot < 0)
-	return -1;
+        return -1;
   use_slot:
     if (encoding_required) {
-	if (slot >= _encoding_required.size())
-	    _encoding_required.resize(slot + 1, false);
-	_encoding_required[slot] = true;
-	this->encode(slot, what);
+        if (slot >= _encoding_required.size())
+            _encoding_required.resize(slot + 1, false);
+        _encoding_required[slot] = true;
+        this->encode(slot, what);
     }
     return slot;
 }
@@ -229,51 +229,51 @@ tokenize(const String &s, int &pos_in, i
     int len = s.length();
     int pos = pos_in;
     while (1) {
-	// skip whitespace
-	while (pos < len && isspace((unsigned char) data[pos])) {
-	    if (data[pos] == '\n')
-		line++;
-	    else if (data[pos] == '\r' && (pos + 1 == len || data[pos+1] != '\n'))
-		line++;
-	    pos++;
-	}
-
-	if (pos >= len) {
-	    pos_in = len;
-	    return String();
-	} else if (data[pos] == '%') {
-	    for (pos++; pos < len && data[pos] != '\n' && data[pos] != '\r'; pos++)
-		/* nada */;
-	} else if (data[pos] == '[' || data[pos] == ']' || data[pos] == '{' || data[pos] == '}') {
-	    pos_in = pos + 1;
-	    return s.substring(pos, 1);
-	} else if (data[pos] == '(') {
-	    int first = pos, nest = 0;
-	    for (pos++; pos < len && (data[pos] != ')' || nest); pos++)
-		switch (data[pos]) {
-		  case '(': nest++; break;
-		  case ')': nest--; break;
-		  case '\\':
-		    if (pos + 1 < len)
-			pos++;
-		    break;
-		  case '\n': line++; break;
-		  case '\r':
-		    if (pos + 1 == len || data[pos+1] != '\n')
-			line++;
-		    break;
-		}
-	    pos_in = (pos < len ? pos + 1 : len);
-	    return s.substring(first, pos_in - first);
-	} else {
-	    int first = pos;
-	    while (pos < len && data[pos] == '/')
-		pos++;
-	    while (pos < len && data[pos] != '/' && !isspace((unsigned char) data[pos]) && data[pos] != '[' && data[pos] != ']' && data[pos] != '%' && data[pos] != '(' && data[pos] != '{' && data[pos] != '}')
-		pos++;
-	    pos_in = pos;
-	    return s.substring(first, pos - first);
-	}
+        // skip whitespace
+        while (pos < len && isspace((unsigned char) data[pos])) {
+            if (data[pos] == '\n')
+                line++;
+            else if (data[pos] == '\r' && (pos + 1 == len || data[pos+1] != '\n'))
+                line++;
+            pos++;
+        }
+
+        if (pos >= len) {
+            pos_in = len;
+            return String();
+        } else if (data[pos] == '%') {
+            for (pos++; pos < len && data[pos] != '\n' && data[pos] != '\r'; pos++)
+                /* nada */;
+        } else if (data[pos] == '[' || data[pos] == ']' || data[pos] == '{' || data[pos] == '}') {
+            pos_in = pos + 1;
+            return s.substring(pos, 1);
+        } else if (data[pos] == '(') {
+            int first = pos, nest = 0;
+            for (pos++; pos < len && (data[pos] != ')' || nest); pos++)
+                switch (data[pos]) {
+                  case '(': nest++; break;
+                  case ')': nest--; break;
+                  case '\\':
+                    if (pos + 1 < len)
+                        pos++;
+                    break;
+                  case '\n': line++; break;
+                  case '\r':
+                    if (pos + 1 == len || data[pos+1] != '\n')
+                        line++;
+                    break;
+                }
+            pos_in = (pos < len ? pos + 1 : len);
+            return s.substring(first, pos_in - first);
+        } else {
+            int first = pos;
+            while (pos < len && data[pos] == '/')
+                pos++;
+            while (pos < len && data[pos] != '/' && !isspace((unsigned char) data[pos]) && data[pos] != '[' && data[pos] != ']' && data[pos] != '%' && data[pos] != '(' && data[pos] != '{' && data[pos] != '}')
+                pos++;
+            pos_in = pos;
+            return s.substring(first, pos - first);
+        }
     }
 }
 
@@ -285,43 +285,43 @@ comment_tokenize(const String &s, int &p
     int len = s.length();
     int pos = pos_in;
     while (1) {
-	while (pos < len && data[pos] != '%' && data[pos] != '(') {
-	    if (data[pos] == '\n')
-		line++;
-	    else if (data[pos] == '\r' && (pos + 1 == len || data[pos+1] != '\n'))
-		line++;
-	    pos++;
-	}
-
-	if (pos >= len) {
-	    pos_in = len;
-	    return String();
-	} else if (data[pos] == '%') {
-	    for (pos++; pos < len && (data[pos] == ' ' || data[pos] == '\t'); pos++)
-		/* nada */;
-	    int first = pos;
-	    for (; pos < len && data[pos] != '\n' && data[pos] != '\r'; pos++)
-		/* nada */;
-	    pos_in = pos;
-	    if (pos > first)
-		return s.substring(first, pos - first);
-	} else {
-	    int nest = 0;
-	    for (pos++; pos < len && (data[pos] != ')' || nest); pos++)
-		switch (data[pos]) {
-		  case '(': nest++; break;
-		  case ')': nest--; break;
-		  case '\\':
-		    if (pos + 1 < len)
-			pos++;
-		    break;
-		  case '\n': line++; break;
-		  case '\r':
-		    if (pos + 1 == len || data[pos+1] != '\n')
-			line++;
-		    break;
-		}
-	}
+        while (pos < len && data[pos] != '%' && data[pos] != '(') {
+            if (data[pos] == '\n')
+                line++;
+            else if (data[pos] == '\r' && (pos + 1 == len || data[pos+1] != '\n'))
+                line++;
+            pos++;
+        }
+
+        if (pos >= len) {
+            pos_in = len;
+            return String();
+        } else if (data[pos] == '%') {
+            for (pos++; pos < len && (data[pos] == ' ' || data[pos] == '\t'); pos++)
+                /* nada */;
+            int first = pos;
+            for (; pos < len && data[pos] != '\n' && data[pos] != '\r'; pos++)
+                /* nada */;
+            pos_in = pos;
+            if (pos > first)
+                return s.substring(first, pos - first);
+        } else {
+            int nest = 0;
+            for (pos++; pos < len && (data[pos] != ')' || nest); pos++)
+                switch (data[pos]) {
+                  case '(': nest++; break;
+                  case ')': nest--; break;
+                  case '\\':
+                    if (pos + 1 < len)
+                        pos++;
+                    break;
+                  case '\n': line++; break;
+                  case '\r':
+                    if (pos + 1 == len || data[pos+1] != '\n')
+                        line++;
+                    break;
+                }
+        }
     }
 }
 
@@ -329,7 +329,7 @@ static bool
 retokenize_isword(char c)
 {
     return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
-	|| (c >= '0' && c <= '9') || c == '.' || c == '_';
+        || (c >= '0' && c <= '9') || c == '.' || c == '_';
 }
 
 
@@ -352,8 +352,8 @@ static int
 find_ligkern_op(const String &s)
 {
     for (int i = 0; ligkern_ops[i].s; i++)
-	if (ligkern_ops[i].s == s)
-	    return ligkern_ops[i].v;
+        if (ligkern_ops[i].s == s)
+            return ligkern_ops[i].v;
     return 0;
 }
 
@@ -368,16 +368,16 @@ DvipsEncoding::add_ligkern(const Ligatur
 {
     Ligature *old = std::find(_lig.begin(), _lig.end(), l);
     if (old == _lig.end())
-	_lig.push_back(l);
+        _lig.push_back(l);
     else {
-	if ((l.join & JT_KERN) && (override > 0 || !(old->join & JT_KERN))) {
-	    old->join |= JT_KERN;
-	    old->k = l.k;
-	}
-	if ((l.join & JT_LIG) && (override > 0 || !(old->join & JT_LIG))) {
-	    old->join = (old->join & JT_KERN) | (l.join & JT_LIGALL);
-	    old->d = l.d;
-	}
+        if ((l.join & JT_KERN) && (override > 0 || !(old->join & JT_KERN))) {
+            old->join |= JT_KERN;
+            old->k = l.k;
+        }
+        if ((l.join & JT_LIG) && (override > 0 || !(old->join & JT_LIG))) {
+            old->join = (old->join & JT_KERN) | (l.join & JT_LIGALL);
+            old->d = l.d;
+        }
     }
 }
 
@@ -389,107 +389,107 @@ DvipsEncoding::parse_ligkern_words(Vecto
     long l;
     char *endptr;
     if (v.size() == 3) {
-	// empty string fails
-	if (!v[0])
-	    return -1;
-	// boundary char setting
-	if (v[0] == "||" && v[1] == "=") {
-	    char *endptr;
-	    if (override > 0 || _boundary_char < 0)
-		_boundary_char = strtol(v[2].c_str(), &endptr, 10);
-	    if (*endptr == 0 && _boundary_char < _e.size())
-		return 0;
-	    else
-		return errh->error("parse error in boundary character assignment");
-	}
-	// altselector char setting
-	if (v[0] == "^^" && v[1] == "=") {
-	    char *endptr;
-	    if (override > 0 || _altselector_char < 0)
-		_altselector_char = strtol(v[2].c_str(), &endptr, 10);
-	    if (*endptr == 0 && _altselector_char < _e.size())
-		return 0;
-	    else
-		return errh->error("parse error in altselector character assignment");
-	}
-	// encoding
-	l = strtol(v[0].c_str(), &endptr, 0);
-	if (endptr == v[0].end() && v[1] == "=") {
-	    if (l >= 0 && l < 256) {
-		if (override > 0 || !_e[l])
-		    encode(l, v[2]);
-		return 0;
-	    } else
-		return errh->error("encoding value %<%d%> out of range", l);
-	}
-
-	// kern operation
-	if (v[1].length() >= 3 && v[1][0] == '{' && v[1].back() == '}') {
-	    String middle = v[1].substring(1, v[1].length() - 2);
-	    l = strtol(middle.c_str(), &endptr, 0);
-	    if (endptr == middle.end()) {
-		op = JT_KERN;
-		goto found_kernop;
-	    }
-	}
-	op = find_ligkern_op(v[1]);
-	if (!op || (op & JT_ADDLIG))
-	    return -1;
+        // empty string fails
+        if (!v[0])
+            return -1;
+        // boundary char setting
+        if (v[0] == "||" && v[1] == "=") {
+            char *endptr;
+            if (override > 0 || _boundary_char < 0)
+                _boundary_char = strtol(v[2].c_str(), &endptr, 10);
+            if (*endptr == 0 && _boundary_char < _e.size())
+                return 0;
+            else
+                return errh->error("parse error in boundary character assignment");
+        }
+        // altselector char setting
+        if (v[0] == "^^" && v[1] == "=") {
+            char *endptr;
+            if (override > 0 || _altselector_char < 0)
+                _altselector_char = strtol(v[2].c_str(), &endptr, 10);
+            if (*endptr == 0 && _altselector_char < _e.size())
+                return 0;
+            else
+                return errh->error("parse error in altselector character assignment");
+        }
+        // encoding
+        l = strtol(v[0].c_str(), &endptr, 0);
+        if (endptr == v[0].end() && v[1] == "=") {
+            if (l >= 0 && l < 256) {
+                if (override > 0 || !_e[l])
+                    encode(l, v[2]);
+                return 0;
+            } else
+                return errh->error("encoding value %<%d%> out of range", l);
+        }
+
+        // kern operation
+        if (v[1].length() >= 3 && v[1][0] == '{' && v[1].back() == '}') {
+            String middle = v[1].substring(1, v[1].length() - 2);
+            l = strtol(middle.c_str(), &endptr, 0);
+            if (endptr == middle.end()) {
+                op = JT_KERN;
+                goto found_kernop;
+            }
+        }
+        op = find_ligkern_op(v[1]);
+        if (!op || (op & JT_ADDLIG))
+            return -1;
       found_kernop:
-	int av = (v[0] == "*" ? J_ALL : encoding_of(v[0]));
-	if (av < 0)
-	    return errh->warning("bad %<%s%> (%<%s%> has no encoding)", v[1].c_str(), v[0].c_str());
-	int bv = (v[2] == "*" ? J_ALL : encoding_of(v[2]));
-	if (bv < 0)
-	    return errh->warning("bad %<%s%> (%<%s%> has no encoding)", v[1].c_str(), v[2].c_str());
-	if ((op & JT_KERN) && l && (av == J_ALL || bv == J_ALL))
-	    return errh->warning("%<%s %s %s%> illegal, only {0} works with *", v[0].c_str(), v[1].c_str(), v[2].c_str());
-	Ligature lig = { av, bv, op, static_cast<int>(l), 0 };
-	add_ligkern(lig, override);
-	return 0;
+        int av = (v[0] == "*" ? J_ALL : encoding_of(v[0]));
+        if (av < 0)
+            return errh->warning("bad %<%s%> (%<%s%> has no encoding)", v[1].c_str(), v[0].c_str());
+        int bv = (v[2] == "*" ? J_ALL : encoding_of(v[2]));
+        if (bv < 0)
+            return errh->warning("bad %<%s%> (%<%s%> has no encoding)", v[1].c_str(), v[2].c_str());
+        if ((op & JT_KERN) && l && (av == J_ALL || bv == J_ALL))
+            return errh->warning("%<%s %s %s%> illegal, only {0} works with *", v[0].c_str(), v[1].c_str(), v[2].c_str());
+        Ligature lig = { av, bv, op, static_cast<int>(l), 0 };
+        add_ligkern(lig, override);
+        return 0;
 
     } else if (v.size() == 4 && ((op = find_ligkern_op(v[2])) & JT_ADDLIG)) {
-	int av = encoding_of(v[0], override > 0);
-	if (av < 0)
-	    return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[0].c_str()) : -1);
-	int bv = encoding_of(v[1], override > 0);
-	if (bv < 0)
-	    return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[1].c_str()) : -1);
-	int cv = encoding_of(v[3], override > 0);
-	if (cv < 0)
-	    return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[3].c_str()) : -1);
-	Ligature lig = { av, bv, op, 0, cv };
-	add_ligkern(lig, override);
-	return 0;
+        int av = encoding_of(v[0], override > 0);
+        if (av < 0)
+            return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[0].c_str()) : -1);
+        int bv = encoding_of(v[1], override > 0);
+        if (bv < 0)
+            return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[1].c_str()) : -1);
+        int cv = encoding_of(v[3], override > 0);
+        if (cv < 0)
+            return (override > 0 ? errh->warning("bad ligature (%<%s%> has no encoding)", v[3].c_str()) : -1);
+        Ligature lig = { av, bv, op, 0, cv };
+        add_ligkern(lig, override);
+        return 0;
 
     } else
-	return -EPARSE;
+        return -EPARSE;
 }
 
 int
 DvipsEncoding::parse_position_words(Vector<String> &v, int override, ErrorHandler *errh)
 {
     if (v.size() != 4)
-	return -EPARSE;
+        return -EPARSE;
 
     int c = encoding_of(v[0]);
     if (c < 0)
-	return (override > 0 ? errh->warning("bad positioning (%<%s%> has no encoding)", v[0].c_str()) : -1);
+        return (override > 0 ? errh->warning("bad positioning (%<%s%> has no encoding)", v[0].c_str()) : -1);
 
     char *endptr;
     int pdx, pdy, adx;
     if (!v[1] || !v[2] || !v[3]
-	|| (pdx = strtol(v[1].c_str(), &endptr, 10), *endptr)
-	|| (pdy = strtol(v[2].c_str(), &endptr, 10), *endptr)
-	|| (adx = strtol(v[3].c_str(), &endptr, 10), *endptr))
-	return errh->error("parse error in POSITION");
+        || (pdx = strtol(v[1].c_str(), &endptr, 10), *endptr)
+        || (pdy = strtol(v[2].c_str(), &endptr, 10), *endptr)
+        || (adx = strtol(v[3].c_str(), &endptr, 10), *endptr))
+        return errh->error("parse error in POSITION");
 
     Ligature l = { c, pdx, pdy, adx, 0 };
     Ligature *old = std::find(_pos.begin(), _pos.end(), l);
     if (old == _pos.end())
-	_pos.push_back(l);
+        _pos.push_back(l);
     else if (override > 0)
-	*old = l;
+        *old = l;
     return 0;
 }
 
@@ -498,31 +498,31 @@ DvipsEncoding::parse_unicoding_words(Vec
 {
     int av;
     if (v.size() < 2 || (v[1] != "=" && v[1] != "=:" && v[1] != ":="))
-	return -EPARSE;
+        return -EPARSE;
     else if (v[0] == "||" || (av = encoding_of(v[0])) < 0)
-	return errh->warning("bad UNICODING (%<%s%> has no encoding)", v[0].c_str());
+        return errh->warning("bad UNICODING (%<%s%> has no encoding)", v[0].c_str());
 
     int original_size = _unicoding.size();
 
     if (v.size() == 2 || (v.size() == 3 && v[2] == dot_notdef))
-	/* no warnings to delete a glyph */;
+        /* no warnings to delete a glyph */;
     else {
-	for (int i = 2; i < v.size(); i++) {
-	    if (_unicoding.size() != original_size)
-		_unicoding.push_back(GLYPHLIST_ALTERNATIVE);
-	    if (!glyphname_unicode(v[i], _unicoding)) {
-		errh->warning("can%,t map %<%s%> to Unicode", v[i].c_str());
-		if (i == v.size() - 1 && _unicoding.size() == original_size)
-		    errh->warning("target %<%s%> will be deleted from encoding", v[0].c_str());
-		else if (_unicoding.size() != original_size)
-		    _unicoding.pop_back();
-	    }
-	}
+        for (int i = 2; i < v.size(); i++) {
+            if (_unicoding.size() != original_size)
+                _unicoding.push_back(GLYPHLIST_ALTERNATIVE);
+            if (!glyphname_unicode(v[i], _unicoding)) {
+                errh->warning("can%,t map %<%s%> to Unicode", v[i].c_str());
+                if (i == v.size() - 1 && _unicoding.size() == original_size)
+                    errh->warning("target %<%s%> will be deleted from encoding", v[0].c_str());
+                else if (_unicoding.size() != original_size)
+                    _unicoding.pop_back();
+            }
+        }
     }
 
     _unicoding.push_back(0);
     if (override > 0 || _unicoding_map[v[0]] < 0)
-	_unicoding_map.insert(v[0], original_size);
+        _unicoding_map.insert(v[0], original_size);
     return 0;
 }
 
@@ -536,31 +536,31 @@ void
 DvipsEncoding::parse_word_group(Vector<String> &words, int override, int wt, ErrorHandler *errh)
 {
     if (words.size() > 0) {
-	int (DvipsEncoding::*method)(Vector<String> &, int, ErrorHandler *) = word_types[wt].parsefunc;
-	if ((this->*method)(words, override, errh) == -EPARSE) {
-	    Vector<String> rewords;
-	    for (String *sp = words.begin(); sp != words.end(); sp++) {
-		const char *s = sp->begin(), *ends = sp->end();
-		while (s != ends) {
-		    const char *word = s;
-		    if (*s == '{') {
-			for (s++; s != ends && *s != '}'; s++)
-			    /* nada */;
-			if (s != ends)
-			    s++;
-		    } else {
-			bool x = retokenize_isword(*s);
-			for (s++; s != ends && x == retokenize_isword(*s); s++)
-			    /* nada */;
-		    }
-		    rewords.push_back(sp->substring(word, s));
-		}
-	    }
-	    if ((this->*method)(rewords, override, errh) == -EPARSE)
-		errh->error("parse error in %s", word_types[wt].name);
+        int (DvipsEncoding::*method)(Vector<String> &, int, ErrorHandler *) = word_types[wt].parsefunc;
+        if ((this->*method)(words, override, errh) == -EPARSE) {
+            Vector<String> rewords;
+            for (String *sp = words.begin(); sp != words.end(); sp++) {
+                const char *s = sp->begin(), *ends = sp->end();
+                while (s != ends) {
+                    const char *word = s;
+                    if (*s == '{') {
+                        for (s++; s != ends && *s != '}'; s++)
+                            /* nada */;
+                        if (s != ends)
+                            s++;
+                    } else {
+                        bool x = retokenize_isword(*s);
+                        for (s++; s != ends && x == retokenize_isword(*s); s++)
+                            /* nada */;
+                    }
+                    rewords.push_back(sp->substring(word, s));
+                }
+            }
+            if ((this->*method)(rewords, override, errh) == -EPARSE)
+                errh->error("parse error in %s", word_types[wt].name);
 
-	}
-	words.clear();
+        }
+        words.clear();
     }
 }
 
@@ -571,16 +571,16 @@ DvipsEncoding::parse_words(const String
     const char *data = s.data();
     const char *end = s.end();
     while (data < end) {
-	while (data < end && isspace((unsigned char) *data))
-	    data++;
-	const char *first = data;
-	while (data < end && !isspace((unsigned char) *data) && *data != ';')
-	    data++;
-	if (data == first) {
-	    data++;		// step past semicolon (or harmlessly past EOS)
-	    parse_word_group(words, override, wt, errh);
-	} else
-	    words.push_back(s.substring(first, data));
+        while (data < end && isspace((unsigned char) *data))
+            data++;
+        const char *first = data;
+        while (data < end && !isspace((unsigned char) *data) && *data != ';')
+            data++;
+        if (data == first) {
+            data++;             // step past semicolon (or harmlessly past EOS)
+            parse_word_group(words, override, wt, errh);
+        } else
+            words.push_back(s.substring(first, data));
     }
     parse_word_group(words, override, wt, errh);
     return 0;
@@ -598,14 +598,14 @@ static String
 trim_space(const String &s, int pos)
 {
     while (pos < s.length() && isspace((unsigned char) s[pos]))
-	pos++;
+        pos++;
     int epos = s.length();
     for (int x = 0; x < 2; x++) {
-	while (epos > pos && isspace((unsigned char) s[epos - 1]))
-	    epos--;
-	if (epos == pos || s[epos - 1] != ';')
-	    break;
-	epos--;
+        while (epos > pos && isspace((unsigned char) s[epos - 1]))
+            epos--;
+        if (epos == pos || s[epos - 1] != ';')
+            break;
+        epos--;
     }
     return s.substring(pos, epos - pos);
 }
@@ -616,7 +616,7 @@ DvipsEncoding::parse(String filename, bo
     int before = errh->nerrors();
     String s = read_file(filename, errh);
     if (errh->nerrors() != before)
-	return -1;
+        return -1;
     _filename = filename;
     _printable_filename = printable_filename(filename);
     _file_had_ligkern = false;
@@ -625,15 +625,15 @@ DvipsEncoding::parse(String filename, bo
     // parse text
     String token = tokenize(s, pos, line);
     if (!token || token[0] != '/')
-	return errh->lerror(landmark(line), "parse error, expected name");
+        return errh->lerror(landmark(line), "parse error, expected name");
     _name = token.substring(1);
     _initial_comment = s.substring(0, pos - token.length());
 
     if (tokenize(s, pos, line) != "[")
-	return errh->lerror(landmark(line), "parse error, expected [");
+        return errh->lerror(landmark(line), "parse error, expected [");
 
     while ((token = tokenize(s, pos, line)) && token[0] == '/')
-	_e.push_back(token.substring(1));
+        _e.push_back(token.substring(1));
 
     _final_text = token + s.substring(pos);
 
@@ -642,59 +642,59 @@ DvipsEncoding::parse(String filename, bo
     Vector<String> words;
     LandmarkErrorHandler lerrh(errh, "");
     while ((token = comment_tokenize(s, pos, line)))
-	if (token.length() >= 8
-	    && memcmp(token.data(), "LIGKERN", 7) == 0
-	    && isspace((unsigned char) token[7])
-	    && !ignore_ligkern) {
-	    lerrh.set_landmark(landmark(line));
-	    parse_words(token.substring(8), 1, WT_LIGKERN, &lerrh);
-
-	} else if (token.length() >= 9
-		   && memcmp(token.data(), "LIGKERNX", 8) == 0
-		   && isspace((unsigned char) token[8])
-		   && !ignore_ligkern) {
-	    lerrh.set_landmark(landmark(line));
-	    parse_words(token.substring(9), 1, WT_LIGKERN, &lerrh);
-
-	} else if (token.length() >= 10
-		   && memcmp(token.data(), "UNICODING", 9) == 0
-		   && isspace((unsigned char) token[9])
-		   && !ignore_other) {
-	    lerrh.set_landmark(landmark(line));
-	    parse_words(token.substring(10), 1, WT_UNICODING, &lerrh);
-
-	} else if (token.length() >= 9
-		   && memcmp(token.data(), "POSITION", 8) == 0
-		   && isspace((unsigned char) token[8])
-		   && !ignore_other) {
-	    lerrh.set_landmark(landmark(line));
-	    parse_words(token.substring(9), 1, WT_POSITION, &lerrh);
-
-	} else if (token.length() >= 13
-		   && memcmp(token.data(), "CODINGSCHEME", 12) == 0
-		   && isspace((unsigned char) token[12])
-		   && !ignore_other) {
-	    _coding_scheme = trim_space(token, 13);
-	    if (_coding_scheme.length() > 39)
-		lerrh.lwarning(landmark(line), "only first 39 chars of CODINGSCHEME are significant");
-	    if (std::find(_coding_scheme.begin(), _coding_scheme.end(), '(') < _coding_scheme.end()
-		|| std::find(_coding_scheme.begin(), _coding_scheme.end(), ')') < _coding_scheme.end()) {
-		lerrh.lerror(landmark(line), "CODINGSCHEME cannot contain parentheses");
-		_coding_scheme = String();
-	    }
-
-	} else if (token.length() >= 11
-		   && memcmp(token.data(), "WARNMISSING", 11) == 0
-		   && (token.length() == 11 || isspace((unsigned char) token[11]))
-		   && !ignore_other) {
-	    String value = trim_space(token, 11);
-	    if (value == "1" || value == "yes" || value == "true" || !value)
-		_warn_missing = true;
-	    else if (value == "0" || value == "no" || value == "false")
-		_warn_missing = false;
-	    else
-		lerrh.lerror(landmark(line), "WARNMISSING command not understood");
-	}
+        if (token.length() >= 8
+            && memcmp(token.data(), "LIGKERN", 7) == 0
+            && isspace((unsigned char) token[7])
+            && !ignore_ligkern) {
+            lerrh.set_landmark(landmark(line));
+            parse_words(token.substring(8), 1, WT_LIGKERN, &lerrh);
+
+        } else if (token.length() >= 9
+                   && memcmp(token.data(), "LIGKERNX", 8) == 0
+                   && isspace((unsigned char) token[8])
+                   && !ignore_ligkern) {
+            lerrh.set_landmark(landmark(line));
+            parse_words(token.substring(9), 1, WT_LIGKERN, &lerrh);
+
+        } else if (token.length() >= 10
+                   && memcmp(token.data(), "UNICODING", 9) == 0
+                   && isspace((unsigned char) token[9])
+                   && !ignore_other) {
+            lerrh.set_landmark(landmark(line));
+            parse_words(token.substring(10), 1, WT_UNICODING, &lerrh);
+
+        } else if (token.length() >= 9
+                   && memcmp(token.data(), "POSITION", 8) == 0
+                   && isspace((unsigned char) token[8])
+                   && !ignore_other) {
+            lerrh.set_landmark(landmark(line));
+            parse_words(token.substring(9), 1, WT_POSITION, &lerrh);
+
+        } else if (token.length() >= 13
+                   && memcmp(token.data(), "CODINGSCHEME", 12) == 0
+                   && isspace((unsigned char) token[12])
+                   && !ignore_other) {
+            _coding_scheme = trim_space(token, 13);
+            if (_coding_scheme.length() > 39)
+                lerrh.lwarning(landmark(line), "only first 39 chars of CODINGSCHEME are significant");
+            if (std::find(_coding_scheme.begin(), _coding_scheme.end(), '(') < _coding_scheme.end()
+                || std::find(_coding_scheme.begin(), _coding_scheme.end(), ')') < _coding_scheme.end()) {
+                lerrh.lerror(landmark(line), "CODINGSCHEME cannot contain parentheses");
+                _coding_scheme = String();
+            }
+
+        } else if (token.length() >= 11
+                   && memcmp(token.data(), "WARNMISSING", 11) == 0
+                   && (token.length() == 11 || isspace((unsigned char) token[11]))
+                   && !ignore_other) {
+            String value = trim_space(token, 11);
+            if (value == "1" || value == "yes" || value == "true" || !value)
+                _warn_missing = true;
+            else if (value == "0" || value == "no" || value == "false")
+                _warn_missing = false;
+            else
+                lerrh.lerror(landmark(line), "WARNMISSING command not understood");
+        }
 
     return 0;
 }
@@ -721,23 +721,23 @@ void
 DvipsEncoding::bad_codepoint(int code, Metrics &metrics, HashMap<PermString, int> &unencoded)
 {
     for (int i = 0; i < _lig.size(); i++) {
-	Ligature &l = _lig[i];
-	if (l.c1 == code || l.c2 == code)
-	    l.join = 0;
-	else if ((l.join & JT_ADDLIG) && l.d == code)
-	    l.join &= ~JT_LIGALL;
+        Ligature &l = _lig[i];
+        if (l.c1 == code || l.c2 == code)
+            l.join = 0;
+        else if ((l.join & JT_ADDLIG) && l.d == code)
+            l.join &= ~JT_LIGALL;
     }
 
     if (_warn_missing) {
-	Vector<uint32_t> garbage;
-	bool unicodes_explicit = x_unicodes(_e[code], garbage);
-	if (!unicodes_explicit || garbage.size() > 0) {
-	    Vector<Setting> v;
-	    v.push_back(Setting(Setting::RULE, 500, 500));
-	    v.push_back(Setting(Setting::SPECIAL, String("Warning: missing glyph '") + _e[code] + "'"));
-	    metrics.encode_virtual(code, _e[code], 0, v, true);
-	    unencoded.insert(_e[code], 1);
-	}
+        Vector<uint32_t> garbage;
+        bool unicodes_explicit = x_unicodes(_e[code], garbage);
+        if (!unicodes_explicit || garbage.size() > 0) {
+            Vector<Setting> v;
+            v.push_back(Setting(Setting::RULE, 500, 500));
+            v.push_back(Setting(Setting::SPECIAL, String("Warning: missing glyph '") + _e[code] + "'"));
+            metrics.encode_virtual(code, _e[code], 0, v, true);
+            unencoded.insert(_e[code], 1);
+        }
     }
 }
 
@@ -745,9 +745,9 @@ static inline Efont::OpenType::Glyph
 map_uni(uint32_t uni, const Efont::OpenType::Cmap &cmap, const Metrics &m)
 {
     if (uni == U_EMPTYSLOT)
-	return m.emptyslot_glyph();
+        return m.emptyslot_glyph();
     else
-	return cmap.map_uni(uni);
+        return cmap.map_uni(uni);
 }
 
 bool
@@ -755,12 +755,12 @@ DvipsEncoding::x_unicodes(PermString chn
 {
     int i = _unicoding_map[chname];
     if (i >= 0) {
-	for (; _unicoding[i] > 0; i++)
-	    unicodes.push_back(_unicoding[i]);
-	return true;
+        for (; _unicoding[i] > 0; i++)
+            unicodes.push_back(_unicoding[i]);
+        return true;
     } else {
-	glyphname_unicode(chname, unicodes);
-	return false;
+        glyphname_unicode(chname, unicodes);
+        return false;
     }
 }
 
@@ -770,144 +770,144 @@ DvipsEncoding::make_metrics(Metrics &met
 {
     // first pass: without secondaries
     for (int code = 0; code < _e.size(); code++) {
-	PermString chname = _e[code];
+        PermString chname = _e[code];
 
-	// common case: skip .notdef
-	if (chname == dot_notdef)
-	    continue;
-
-	// find first single Unicode glyph supported by the font
-	Efont::OpenType::Glyph glyph = 0;
-	uint32_t glyph_uni = 0;
-	{
-	    Vector<uint32_t> unicodes;
-	    (void) x_unicodes(chname, unicodes);
-	    Vector<uint32_t>::iterator u = unicodes.begin();
-	    while (u != unicodes.end() && glyph <= 0) {
-		uint32_t this_uni = u[0];
-		++u;
-		if (u != unicodes.end()) {
-		    if (*u != GLYPHLIST_ALTERNATIVE)
-			break;
-		    ++u;
-		}
-
-		glyph = map_uni(this_uni, *finfo.cmap, metrics);
-		if (glyph_uni == 0 || glyph > 0)
-		    glyph_uni = this_uni;
-	    }
-	}
+        // common case: skip .notdef
+        if (chname == dot_notdef)
+            continue;
+
+        // find first single Unicode glyph supported by the font
+        Efont::OpenType::Glyph glyph = 0;
+        uint32_t glyph_uni = 0;
+        {
+            Vector<uint32_t> unicodes;
+            (void) x_unicodes(chname, unicodes);
+            Vector<uint32_t>::iterator u = unicodes.begin();
+            while (u != unicodes.end() && glyph <= 0) {
+                uint32_t this_uni = u[0];
+                ++u;
+                if (u != unicodes.end()) {
+                    if (*u != GLYPHLIST_ALTERNATIVE)
+                        break;
+                    ++u;
+                }
+
+                glyph = map_uni(this_uni, *finfo.cmap, metrics);
+                if (glyph_uni == 0 || glyph > 0)
+                    glyph_uni = this_uni;
+            }
+        }
 
-	// find named glyph, if any
-	Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
+        // find named glyph, if any
+        Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
 #if 0
-	// 2.May.2008: ff, fi, fl, ffi, and ffl might map to f_f, f_i, f_l,
-	// f_f_i, and f_f_l
-	if (!named_glyph && chname.length() > 0 && chname.length() <= 3
-	    && chname[0] == 'f') {
-	    if (chname.equals("ff", 2))
-		named_glyph = finfo.glyphid("f_f");
-	    else if (chname.equals("fi", 2))
-		named_glyph = finfo.glyphid("f_i");
-	    else if (chname.equals("fl", 2))
-		named_glyph = finfo.glyphid("f_l");
-	    else if (chname.equals("ffi", 2))
-		named_glyph = finfo.glyphid("f_f_i");
-	    else if (chname.equals("ffl", 2))
-		named_glyph = finfo.glyphid("f_f_l");
-	}
+        // 2.May.2008: ff, fi, fl, ffi, and ffl might map to f_f, f_i, f_l,
+        // f_f_i, and f_f_l
+        if (!named_glyph && chname.length() > 0 && chname.length() <= 3
+            && chname[0] == 'f') {
+            if (chname.equals("ff", 2))
+                named_glyph = finfo.glyphid("f_f");
+            else if (chname.equals("fi", 2))
+                named_glyph = finfo.glyphid("f_i");
+            else if (chname.equals("fl", 2))
+                named_glyph = finfo.glyphid("f_l");
+            else if (chname.equals("ffi", 2))
+                named_glyph = finfo.glyphid("f_f_i");
+            else if (chname.equals("ffl", 2))
+                named_glyph = finfo.glyphid("f_f_l");
+        }
 #endif
-	// do not use a Unicode-mapped glyph if literal
-	if (literal)
-	    glyph = named_glyph;
-
-	// If we found a glyph, maybe use its named_glyph variant.
-	if (glyph > 0 && named_glyph > 0
-	    && std::find(chname.begin(), chname.end(), '.') < chname.end())
-	    glyph = named_glyph;
-
-	// assign slot
-	if (glyph > 0)
-	    metrics.encode(code, glyph_uni, glyph);
+        // do not use a Unicode-mapped glyph if literal
+        if (literal)
+            glyph = named_glyph;
+
+        // If we found a glyph, maybe use its named_glyph variant.
+        if (glyph > 0 && named_glyph > 0
+            && std::find(chname.begin(), chname.end(), '.') < chname.end())
+            glyph = named_glyph;
+
+        // assign slot
+        if (glyph > 0)
+            metrics.encode(code, glyph_uni, glyph);
     }
 
     // second pass: with secondaries
     for (int code = 0; code < _e.size(); code++) {
-	// skip already-encoded characters and .notdef
-	if (literal || metrics.glyph(code) > 0 || _e[code] == dot_notdef)
-	    continue;
-
-	PermString chname = _e[code];
-
-	// find all Unicodes
-	Vector<uint32_t> unicodes;
-	bool unicodes_explicit = x_unicodes(chname, unicodes);
-
-	// find named glyph, if any
-	Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
-
-	// 1. We were not able to find the glyph using Unicode.
-	// 2. There might be a named_glyph.
-	// May need to try secondaries later.  Store this slot.
-	// Try secondaries, if there's explicit unicoding or no named_glyph.
-	if (unicodes_explicit || named_glyph <= 0)
-	    for (uint32_t *u = unicodes.begin(); u != unicodes.end(); ) {
-		uint32_t *endu = u + 1;
-		while (endu != unicodes.end() && *endu != GLYPHLIST_ALTERNATIVE)
-		    ++endu;
-		if (secondary->encode_uni(code, chname, u, endu, metrics, errh))
-		    goto encoded;
-		u = (endu == unicodes.end() ? endu : endu + 1);
-	    }
-
-	// 1. We were not able to find the glyph using Unicode or secondaries.
-	// 2. There might be a named_glyph.
-	// Use named glyph, if any.  Special case for "UNICODING foo =: ;",
-	// which should turn off the character (even if a named_glyph exists),
-	// UNLESS the glyph was explicitly requested.
-	if (named_glyph > 0
-	    && (!unicodes_explicit
-		|| unicodes.size() > 0
-		|| (_encoding_required.size() > code && _encoding_required[code]))) {
-	    uint32_t uni = 0;
-	    if (unicodes.size() == 1 || (unicodes.size() > 0 && unicodes[1] == GLYPHLIST_ALTERNATIVE))
-		uni = unicodes[0];
-	    metrics.encode(code, uni, named_glyph);
-	}
+        // skip already-encoded characters and .notdef
+        if (literal || metrics.glyph(code) > 0 || _e[code] == dot_notdef)
+            continue;
+
+        PermString chname = _e[code];
+
+        // find all Unicodes
+        Vector<uint32_t> unicodes;
+        bool unicodes_explicit = x_unicodes(chname, unicodes);
+
+        // find named glyph, if any
+        Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
+
+        // 1. We were not able to find the glyph using Unicode.
+        // 2. There might be a named_glyph.
+        // May need to try secondaries later.  Store this slot.
+        // Try secondaries, if there's explicit unicoding or no named_glyph.
+        if (unicodes_explicit || named_glyph <= 0)
+            for (uint32_t *u = unicodes.begin(); u != unicodes.end(); ) {
+                uint32_t *endu = u + 1;
+                while (endu != unicodes.end() && *endu != GLYPHLIST_ALTERNATIVE)
+                    ++endu;
+                if (secondary->encode_uni(code, chname, u, endu, metrics, errh))
+                    goto encoded;
+                u = (endu == unicodes.end() ? endu : endu + 1);
+            }
+
+        // 1. We were not able to find the glyph using Unicode or secondaries.
+        // 2. There might be a named_glyph.
+        // Use named glyph, if any.  Special case for "UNICODING foo =: ;",
+        // which should turn off the character (even if a named_glyph exists),
+        // UNLESS the glyph was explicitly requested.
+        if (named_glyph > 0
+            && (!unicodes_explicit
+                || unicodes.size() > 0
+                || (_encoding_required.size() > code && _encoding_required[code]))) {
+            uint32_t uni = 0;
+            if (unicodes.size() == 1 || (unicodes.size() > 0 && unicodes[1] == GLYPHLIST_ALTERNATIVE))
+                uni = unicodes[0];
+            metrics.encode(code, uni, named_glyph);
+        }
 
       encoded:
-	/* all set */;
+        /* all set */;
     }
 
     // add altselector
     if (_altselector_char >= 0 && _altselector_char < _e.size()) {
-	metrics.add_altselector_code(_altselector_char, 0);
-	if (metrics.glyph(_altselector_char) <= 0 && !literal)
-	    (void) secondary->encode_uni(_altselector_char, "altselector", U_ALTSELECTOR, metrics, errh);
+        metrics.add_altselector_code(_altselector_char, 0);
+        if (metrics.glyph(_altselector_char) <= 0 && !literal)
+            (void) secondary->encode_uni(_altselector_char, "<altselector>", U_ALTSELECTOR, metrics, errh);
     }
 
     // final pass: complain
     HashMap<PermString, int> unencoded_map;
     for (int code = 0; code < _e.size(); code++)
-	if (_e[code] != dot_notdef && metrics.glyph(code) <= 0)
-	    bad_codepoint(code, metrics, unencoded_map);
+        if (_e[code] != dot_notdef && metrics.glyph(code) <= 0)
+            bad_codepoint(code, metrics, unencoded_map);
     Vector<String> unencoded;
     for (HashMap<PermString, int>::iterator it = unencoded_map.begin(); it; ++it)
-	unencoded.push_back(it.key());
+        unencoded.push_back(it.key());
 
     if (unencoded.size() == 1) {
-	errh->warning("%<%s%> glyph not found in font", unencoded[0].c_str());
-	errh->message("(This glyph will appear as a blot and cause warnings if used.)");
+        errh->warning("%<%s%> glyph not found in font", unencoded[0].c_str());
+        errh->message("(This glyph will appear as a blot and cause warnings if used.)");
     } else if (unencoded.size() > 1) {
-	std::sort(unencoded.begin(), unencoded.end());
-	StringAccum sa;
-	for (const String* a = unencoded.begin(); a < unencoded.end(); a++)
-	    sa << *a << ' ';
-	sa.pop_back();
-	sa.append_break_lines(sa.take_string(), 68, "  ");
-	sa.pop_back();
-	errh->warning("%d glyphs not found in font:", unencoded.size());
-	errh->message("%s\n(These glyphs will appear as blots and cause warnings if used.)", sa.c_str());
+        std::sort(unencoded.begin(), unencoded.end());
+        StringAccum sa;
+        for (const String* a = unencoded.begin(); a < unencoded.end(); a++)
+            sa << *a << ' ';
+        sa.pop_back();
+        sa.append_break_lines(sa.take_string(), 68, "  ");
+        sa.pop_back();
+        errh->warning("%d glyphs not found in font:", unencoded.size());
+        errh->message("%s\n(These glyphs will appear as blots and cause warnings if used.)", sa.c_str());
     }
 
     metrics.set_coding_scheme(_coding_scheme);
@@ -918,19 +918,19 @@ DvipsEncoding::make_base_mappings(Vector
 {
     mappings.clear();
     for (int code = 0; code < _e.size(); code++) {
-	PermString chname = _e[code];
+        PermString chname = _e[code];
 
-	// common case: skip .notdef
-	if (chname == dot_notdef)
-	    continue;
-
-	// find named glyph
-	Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
-	if (named_glyph > 0) {
-	    if (mappings.size() <= named_glyph)
-		mappings.resize(named_glyph + 1, -1);
-	    mappings[named_glyph] = code;
-	}
+        // common case: skip .notdef
+        if (chname == dot_notdef)
+            continue;
+
+        // find named glyph
+        Efont::OpenType::Glyph named_glyph = finfo.glyphid(chname);
+        if (named_glyph > 0) {
+            if (mappings.size() <= named_glyph)
+                mappings.resize(named_glyph + 1, -1);
+            mappings[named_glyph] = code;
+        }
     }
 }
 
@@ -940,24 +940,24 @@ DvipsEncoding::apply_ligkern_lig(Metrics
 {
     assert((int)J_ALL == (int)Metrics::CODE_ALL);
     for (const Ligature *l = _lig.begin(); l < _lig.end(); l++) {
-	if (l->c1 < 0 || l->c2 < 0 || l->join < 0 || !(l->join & JT_LIG))
-	    continue;
-	metrics.remove_ligatures(l->c1, l->c2);
-	if (!(l->join & JT_ADDLIG))
-	    /* nada */;
-	else if ((l->join & JT_LIGALL) == JL_LIG)
-	    metrics.add_ligature(l->c1, l->c2, l->d);
-	else if ((l->join & JT_LIGALL) == JL_LIGC)
-	    metrics.add_ligature(l->c1, l->c2, metrics.pair_code(l->d, l->c2));
-	else if ((l->join & JT_LIGALL) == JL_CLIG)
-	    metrics.add_ligature(l->c1, l->c2, metrics.pair_code(l->c1, l->d));
-	else {
-	    static int complex_join_warning = 0;
-	    if (!complex_join_warning) {
-		errh->warning("complex LIGKERN ligature removed (I only support %<=:%>, %<=:|%>, and %<|=:%>)");
-		complex_join_warning = 1;
-	    }
-	}
+        if (l->c1 < 0 || l->c2 < 0 || l->join < 0 || !(l->join & JT_LIG))
+            continue;
+        metrics.remove_ligatures(l->c1, l->c2);
+        if (!(l->join & JT_ADDLIG))
+            /* nada */;
+        else if ((l->join & JT_LIGALL) == JL_LIG)
+            metrics.add_ligature(l->c1, l->c2, l->d);
+        else if ((l->join & JT_LIGALL) == JL_LIGC)
+            metrics.add_ligature(l->c1, l->c2, metrics.pair_code(l->d, l->c2));
+        else if ((l->join & JT_LIGALL) == JL_CLIG)
+            metrics.add_ligature(l->c1, l->c2, metrics.pair_code(l->c1, l->d));
+        else {
+            static int complex_join_warning = 0;
+            if (!complex_join_warning) {
+                errh->warning("complex LIGKERN ligature removed (I only support %<=:%>, %<=:|%>, and %<|=:%>)");
+                complex_join_warning = 1;
+            }
+        }
     }
 }
 
@@ -966,14 +966,14 @@ DvipsEncoding::apply_ligkern_kern(Metric
 {
     assert((int)J_ALL == (int)Metrics::CODE_ALL);
     for (const Ligature *l = _lig.begin(); l < _lig.end(); l++)
-	if (l->c1 >= 0 && l->c2 >= 0 && (l->join & JT_KERN))
-	    metrics.set_kern(l->c1, l->c2, l->k);
+        if (l->c1 >= 0 && l->c2 >= 0 && (l->join & JT_KERN))
+            metrics.set_kern(l->c1, l->c2, l->k);
 }
 
 void
 DvipsEncoding::apply_position(Metrics &metrics, ErrorHandler *) const
 {
     for (const Ligature *l = _pos.begin(); l < _pos.end(); l++)
-	if (l->c1 >= 0)
-	    metrics.add_single_positioning(l->c1, l->c2, l->join, l->k);
+        if (l->c1 >= 0)
+            metrics.add_single_positioning(l->c1, l->c2, l->join, l->k);
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/dvipsencoding.hh	2018-02-23 12:47:54.090971778 -0500
@@ -13,27 +13,27 @@ class DvipsEncoding { public:
 
     static void add_glyphlist(String);
 
-    operator bool() const			{ return _e.size() > 0; }
-    const String &name() const			{ return _name; }
-    const String &filename() const		{ return _filename; }
-    int boundary_char() const			{ return _boundary_char; }
-    const String &coding_scheme() const		{ return _coding_scheme; }
-    void set_coding_scheme(const String &s)	{ _coding_scheme = s; }
-    void set_warn_missing(bool wm)		{ _warn_missing = wm; }
+    operator bool() const                       { return _e.size() > 0; }
+    const String &name() const                  { return _name; }
+    const String &filename() const              { return _filename; }
+    int boundary_char() const                   { return _boundary_char; }
+    const String &coding_scheme() const         { return _coding_scheme; }
+    void set_coding_scheme(const String &s)     { _coding_scheme = s; }
+    void set_warn_missing(bool wm)              { _warn_missing = wm; }
 
     void encode(int, PermString);
     inline int encoding_of(PermString) const;
     int encoding_of(PermString, bool encode);
     inline bool encoded(int e) const;
     inline PermString encoding(int e) const;
-    int encoding_size() const			{ return _e.size(); }
+    int encoding_size() const                   { return _e.size(); }
 
     int parse(String filename, bool ignore_ligkern, bool ignore_other, ErrorHandler *);
     int parse_ligkern(const String &ligkern_text, int override, ErrorHandler *);
     int parse_position(const String &ligkern_text, int override, ErrorHandler *);
     int parse_unicoding(const String &unicoding_text, int override, ErrorHandler *);
 
-    bool file_had_ligkern() const		{ return _file_had_ligkern; }
+    bool file_had_ligkern() const               { return _file_had_ligkern; }
 
     // also modifies 'this':
     void make_metrics(Metrics &, const FontInfo &, Secondary *, bool literal, ErrorHandler *);
@@ -44,17 +44,17 @@ class DvipsEncoding { public:
     void apply_position(Metrics &, ErrorHandler *) const;
 
     enum { JT_KERN = 32, JT_LIG = 64, JT_ADDLIG = 128, JT_LIGALL = 199,
-	   JL_LIG = JT_LIG | JT_ADDLIG, JL_CLIG = JL_LIG | 1,
-	   JL_CLIG_S = JL_LIG | 2, JL_LIGC = JL_LIG | 3,
-	   JL_LIGC_S = JL_LIG | 4, JL_CLIGC = JL_LIG | 5,
-	   JL_CLIGC_S = JL_LIG | 6, JL_CLIGC_SS = JL_LIG | 7,
-	   JT_NOLIGKERN = JT_KERN | JT_LIG,
-	   J_ALL = 0x7FFFFFFF }; // also see nokern_names in dvipsencoding.cc
+           JL_LIG = JT_LIG | JT_ADDLIG, JL_CLIG = JL_LIG | 1,
+           JL_CLIG_S = JL_LIG | 2, JL_LIGC = JL_LIG | 3,
+           JL_LIGC_S = JL_LIG | 4, JL_CLIGC = JL_LIG | 5,
+           JL_CLIGC_S = JL_LIG | 6, JL_CLIGC_SS = JL_LIG | 7,
+           JT_NOLIGKERN = JT_KERN | JT_LIG,
+           J_ALL = 0x7FFFFFFF }; // also see nokern_names in dvipsencoding.cc
 
   private:
 
     struct Ligature {
-	int c1, c2, join, k, d;
+        int c1, c2, join, k, d;
     };
 
     Vector<PermString> _e;
@@ -79,8 +79,8 @@ class DvipsEncoding { public:
     bool _warn_missing;
 
     struct WordType {
-	const char *name;
-	int (DvipsEncoding::*parsefunc)(Vector<String>&, int, ErrorHandler*);
+        const char *name;
+        int (DvipsEncoding::*parsefunc)(Vector<String>&, int, ErrorHandler*);
     };
     static const WordType word_types[];
     enum { WT_LIGKERN = 0, WT_POSITION, WT_UNICODING };
@@ -114,9 +114,9 @@ inline PermString
 DvipsEncoding::encoding(int e) const
 {
     if (encoded(e))
-	return _e[e];
+        return _e[e];
     else
-	return PermString();
+        return PermString();
 }
 
 inline int
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.cc	2018-02-23 12:47:54.090971778 -0500
@@ -1,6 +1,6 @@
 /* glyphfilter.{cc,hh} -- define subsets of characters
  *
- * Copyright (c) 2004-2016 Eddie Kohler
+ * Copyright (c) 2004-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -30,7 +30,7 @@ GlyphFilter::allow(Efont::OpenType::Glyp
 {
     // out-of-range glyphs never match
     if (glyph < 0 || glyph >= glyph_names.size())
-	return false;
+        return false;
 
     String glyph_name = glyph_names[glyph];
     int uniprop = -1;
@@ -39,32 +39,32 @@ GlyphFilter::allow(Efont::OpenType::Glyp
 
     // loop over patterns
     for (const Pattern* p = _patterns.begin(); p < _patterns.end(); p++) {
-	// check pattern type
-	if ((p->type & ~T_TYPEMASK) != ptype)
-	    continue;
-	// check include/exclude
-	if ((p->type & T_EXCLUDE) == 0) {
-	    if (included)
-		continue;
-	    any_includes = true;
-	}
-	// check if there's a match
-	bool match;
-	if (p->data == D_NAME)
-	    match = glob_match(glyph_name, p->pattern);
-	else if (p->data == D_UNIPROP) {
-	    if (uniprop < 0)
-		uniprop = UnicodeProperty::property(unicode);
-	    match = ((uniprop & p->u.uniprop.mask) == p->u.uniprop.value);
-	} else
-	    match = (unicode >= p->u.unirange.low && unicode <= p->u.unirange.high);
-	// act if match
-	if (match == ((p->type & T_NEGATE) == 0)) {
-	    if ((p->type & T_EXCLUDE) == 0)
-		included = true;
-	    else
-		return false;
-	}
+        // check pattern type
+        if ((p->type & ~T_TYPEMASK) != ptype)
+            continue;
+        // check include/exclude
+        if ((p->type & T_EXCLUDE) == 0) {
+            if (included)
+                continue;
+            any_includes = true;
+        }
+        // check if there's a match
+        bool match;
+        if (p->data == D_NAME)
+            match = glob_match(glyph_name, p->pattern);
+        else if (p->data == D_UNIPROP) {
+            if (uniprop < 0)
+                uniprop = UnicodeProperty::property(unicode);
+            match = ((uniprop & p->u.uniprop.mask) == p->u.uniprop.value);
+        } else
+            match = (unicode >= p->u.unirange.low && unicode <= p->u.unirange.high);
+        // act if match
+        if (match == ((p->type & T_NEGATE) == 0)) {
+            if ((p->type & T_EXCLUDE) == 0)
+                included = true;
+            else
+                return false;
+        }
     }
 
     return !any_includes || included;
@@ -83,13 +83,13 @@ GlyphFilter::Pattern::compare(const Glyp
 {
     int cmp = a.type - b.type;
     if (cmp == 0)
-	cmp = a.data - b.data;
+        cmp = a.data - b.data;
     if (cmp == 0)
-	cmp = (int) (a.u.unirange.low - b.u.unirange.low);
+        cmp = (int) (a.u.unirange.low - b.u.unirange.low);
     if (cmp == 0)
-	cmp = (int) (a.u.unirange.high - b.u.unirange.high);
+        cmp = (int) (a.u.unirange.high - b.u.unirange.high);
     if (cmp == 0)
-	cmp = String::compare(a.pattern, b.pattern);
+        cmp = String::compare(a.pattern, b.pattern);
     return cmp;
 }
 
@@ -101,59 +101,59 @@ GlyphFilter::add_pattern(const String& p
     const char* begin = pattern.begin();
     const char* end = pattern.end();
     while (begin < end && isspace((unsigned char) *begin))
-	begin++;
+        begin++;
     if (begin >= end)
-	errh->error("missing pattern");
+        errh->error("missing pattern");
 
     while (begin < end) {
-	const char* word = begin;
-	while (word < end && !isspace((unsigned char) *word))
-	    word++;
-	bool negated = false;
-	if (begin < word && begin[0] == '!')
-	    negated = true, begin++;
-
-	// actually parse clause
-	Pattern p(ptype + (negated ? T_NEGATE : 0));
-
-	// unicode property
-	if (begin + 3 <= word && begin[0] == '<' && word[-1] == '>') {
-	    p.data = D_UNIPROP;
-	    if (UnicodeProperty::parse_property(pattern.substring(begin + 1, word - 1), p.u.uniprop.value, p.u.uniprop.mask))
-		_patterns.push_back(p);
-	    else if (errh)
-		errh->error("unknown Unicode property %<%s%>", pattern.c_str());
-	    goto next_clause;
-	}
-
-	// unicode values
-	{
-	    const char* dash = std::find(begin, word, '-');
-	    if (parse_unicode_number(begin, dash, 2, p.u.unirange.low)) {
-		if (dash == word)
-		    p.u.unirange.high = p.u.unirange.low;
-		else if (dash == word - 1)
-		    p.u.unirange.high = 0xFFFFFFFFU;
-		else if (parse_unicode_number(dash + 1, word, (begin[0] == 'U' ? 1 : 0), p.u.unirange.high))
-		    /* do nothing */;
-		else
-		    goto name_pattern; // assume it's a name
-		p.data = D_UNIRANGE;
-		_patterns.push_back(p);
-		goto next_clause;
-	    }
-	}
+        const char* word = begin;
+        while (word < end && !isspace((unsigned char) *word))
+            word++;
+        bool negated = false;
+        if (begin < word && begin[0] == '!')
+            negated = true, begin++;
+
+        // actually parse clause
+        Pattern p(ptype + (negated ? T_NEGATE : 0));
+
+        // unicode property
+        if (begin + 3 <= word && begin[0] == '<' && word[-1] == '>') {
+            p.data = D_UNIPROP;
+            if (UnicodeProperty::parse_property(pattern.substring(begin + 1, word - 1), p.u.uniprop.value, p.u.uniprop.mask))
+                _patterns.push_back(p);
+            else if (errh)
+                errh->error("unknown Unicode property %<%s%>", pattern.c_str());
+            goto next_clause;
+        }
+
+        // unicode values
+        {
+            const char* dash = std::find(begin, word, '-');
+            if (parse_unicode_number(begin, dash, 2, p.u.unirange.low)) {
+                if (dash == word)
+                    p.u.unirange.high = p.u.unirange.low;
+                else if (dash == word - 1)
+                    p.u.unirange.high = 0xFFFFFFFFU;
+                else if (parse_unicode_number(dash + 1, word, (begin[0] == 'U' ? 1 : 0), p.u.unirange.high))
+                    /* do nothing */;
+                else
+                    goto name_pattern; // assume it's a name
+                p.data = D_UNIRANGE;
+                _patterns.push_back(p);
+                goto next_clause;
+            }
+        }
 
-	// otherwise must be name pattern
+        // otherwise must be name pattern
     name_pattern:
-	p.data = D_NAME;
-	p.pattern = pattern.substring(begin, word);
-	_patterns.push_back(p);
+        p.data = D_NAME;
+        p.pattern = pattern.substring(begin, word);
+        _patterns.push_back(p);
 
-	// move to next clause
+        // move to next clause
       next_clause:
-	for (begin = word; begin < end && isspace((unsigned char) *begin); begin++)
-	    /* nada */;
+        for (begin = word; begin < end && isspace((unsigned char) *begin); begin++)
+            /* nada */;
     }
 }
 
@@ -176,7 +176,7 @@ GlyphFilter::operator+=(const GlyphFilte
     _patterns.reserve(gf._patterns.size());
     const Pattern* end = gf._patterns.end();
     for (const Pattern* p = gf._patterns.begin(); p < end; p++)
-	_patterns.push_back(*p);
+        _patterns.push_back(*p);
     return *this;
 }
 
@@ -184,9 +184,9 @@ GlyphFilter
 operator+(const GlyphFilter& a, const GlyphFilter& b)
 {
     if (!b)
-	return a;
+        return a;
     if (!a)
-	return b;
+        return b;
     GlyphFilter x(a);
     x += b;
     return x;
@@ -196,14 +196,14 @@ bool
 operator==(const GlyphFilter& a, const GlyphFilter& b)
 {
     if (&a == &b)
-	return true;
+        return true;
     if (a._patterns.size() != b._patterns.size())
-	return false;
+        return false;
     const GlyphFilter::Pattern* pa = a._patterns.begin();
     const GlyphFilter::Pattern* pb = b._patterns.begin();
     for (; pa < a._patterns.end(); pa++, pb++)
-	if (!(*pa == *pb))
-	    return false;
+        if (!(*pa == *pb))
+            return false;
     return true;
 }
 
@@ -211,10 +211,10 @@ void
 GlyphFilter::sort()
 {
     if (!_sorted) {
-	std::sort(_patterns.begin(), _patterns.end());
-	Pattern* true_end = std::unique(_patterns.begin(), _patterns.end());
-	_patterns.erase(true_end, _patterns.end());
-	_sorted = true;
+        std::sort(_patterns.begin(), _patterns.end());
+        Pattern* true_end = std::unique(_patterns.begin(), _patterns.end());
+        _patterns.erase(true_end, _patterns.end());
+        _sorted = true;
     }
 }
 
@@ -222,15 +222,15 @@ void
 GlyphFilter::unparse(StringAccum& sa) const
 {
     for (const Pattern* p = _patterns.begin(); p < _patterns.end(); p++) {
-	sa << (p->type & T_DST ? 'D' : 'S') << (p->type & T_NEGATE ? "!" : "") << (p->type & T_EXCLUDE ? "X" : "");
-	if (p->data == D_NAME)
-	    sa << '<' << p->pattern << '>';
-	else if (p->data == D_UNIPROP)
-	    sa << "[UNIPROP:" << p->u.uniprop.mask << '=' << p->u.uniprop.value << ']';
-	else
-	    sa.snprintf(20, "[U+%02x-U+%02x]", p->u.unirange.low, p->u.unirange.high);
-	sa << ' ';
+        sa << (p->type & T_DST ? 'D' : 'S') << (p->type & T_NEGATE ? "!" : "") << (p->type & T_EXCLUDE ? "X" : "");
+        if (p->data == D_NAME)
+            sa << '<' << p->pattern << '>';
+        else if (p->data == D_UNIPROP)
+            sa << "[UNIPROP:" << p->u.uniprop.mask << '=' << p->u.uniprop.value << ']';
+        else
+            sa.snprintf(20, "[U+%02x-U+%02x]", p->u.unirange.low, p->u.unirange.high);
+        sa << ' ';
     }
     if (_patterns.size())
-	sa.pop_back();
+        sa.pop_back();
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/glyphfilter.hh	2018-02-23 12:47:54.091971753 -0500
@@ -6,9 +6,9 @@ class Metrics;
 
 class GlyphFilter { public:
 
-    GlyphFilter()			: _sorted(true) { }
+    GlyphFilter()                       : _sorted(true) { }
 
-    operator bool() const		{ return _patterns.size() != 0; }
+    operator bool() const               { return _patterns.size() != 0; }
 
     inline bool allow_substitution(Efont::OpenType::Glyph glyph, const Vector<PermString>& glyph_names, uint32_t unicode) const;
     inline bool allow_alternate(Efont::OpenType::Glyph glyph, const Vector<PermString>& glyph_names, uint32_t unicode) const;
@@ -17,34 +17,34 @@ class GlyphFilter { public:
     void add_alternate_filter(const String&, bool is_exclude, ErrorHandler*);
 
     friend bool operator==(const GlyphFilter&, const GlyphFilter&);
-    inline bool check_eq(GlyphFilter&);	// may alter both GlyphFilters
+    inline bool check_eq(GlyphFilter&); // may alter both GlyphFilters
 
     GlyphFilter& operator+=(const GlyphFilter&);
 
     void unparse(StringAccum&) const;
 
     struct Pattern {
-	uint16_t type;
-	uint16_t data;
-	union {
-	    struct {
-		int mask;
-		int value;
-	    } uniprop;
-	    struct {
-		uint32_t low;
-		uint32_t high;
-	    } unirange;
-	} u;
-	String pattern;
-	Pattern(uint16_t type);
-	static int compare(const Pattern&, const Pattern&);
+        uint16_t type;
+        uint16_t data;
+        union {
+            struct {
+                int mask;
+                int value;
+            } uniprop;
+            struct {
+                uint32_t low;
+                uint32_t high;
+            } unirange;
+        } u;
+        String pattern;
+        Pattern(uint16_t type);
+        static int compare(const Pattern&, const Pattern&);
     };
 
   private:
 
     enum { T_EXCLUDE = 1, T_NEGATE = 2, T_TYPEMASK = 3,
-	   T_SRC = 0, T_DST = 4 };
+           T_SRC = 0, T_DST = 4 };
     enum { D_NAME, D_UNIPROP, D_UNIRANGE };
 
     Vector<Pattern> _patterns;
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.c.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.c
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.c.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.c	2018-02-23 12:47:54.091971753 -0500
@@ -1,6 +1,6 @@
 /* kpseinterface.{c,h} -- interface with the kpathsea library
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,9 +21,6 @@
 #include <kpathsea/expand.h>
 #include <kpathsea/c-pathch.h>
 #include <kpathsea/tex-file.h>
-#ifdef W32TEX
-#include <kpathsea/variable.h>
-#endif
 #include "kpseinterface.h"
 
 int kpsei_env_sep_char = ENV_SEP;
@@ -89,11 +86,3 @@ kpsei_set_debug_flags(unsigned flags)
 {
     kpathsea_debug = flags;
 }
-
-#ifdef W32TEX
-char*
-kpsei_var_value(const char *name)
-{
-  return kpse_var_value(name);
-}
-#endif
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.h.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.h
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.h.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/kpseinterface.h	2018-02-23 12:47:54.091971753 -0500
@@ -13,10 +13,6 @@ enum { KPSEI_FMT_WEB2C, KPSEI_FMT_ENCODI
 char* kpsei_find_file(const char* name, int format);
 void kpsei_set_debug_flags(unsigned flags);
 
-#ifdef W32TEX
-char* kpsei_var_value(const char *name);
-#endif
-
 #ifdef __cplusplus
 }
 #endif
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/Makefile.am.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/Makefile.am
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/Makefile.am.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/Makefile.am	2018-02-23 12:47:54.091971753 -0500
@@ -11,6 +11,7 @@ otftotfm_SOURCES = \
 	metrics.cc metrics.hh \
 	otftotfm.cc otftotfm.hh \
 	secondary.cc secondary.hh \
+	setting.hh \
 	uniprop.cc uniprop.hh \
 	util.cc util.hh
 EXTRA_otftotfm_SOURCES = kpseinterface.c kpseinterface.h
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.cc	2018-02-23 12:47:54.092971728 -0500
@@ -1,6 +1,6 @@
 /* metrics.{cc,hh} -- an encoding during and after OpenType features
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -35,7 +35,7 @@ Metrics::Metrics(const Efont::Charstring
 Metrics::~Metrics()
 {
     for (Char *c = _encoding.begin(); c != _encoding.end(); c++)
-	delete c->virtual_char;
+        delete c->virtual_char;
 }
 
 int
@@ -54,36 +54,36 @@ Metrics::check() const
     // 2. all 'ligatures' entries with 'in1 == c' are in '_encoding[c].ligs'
     // 3. 'virtual_char' SHOW operations point to valid non-virtual chars
     for (int code = 0; code < _encoding.size(); code++) {
-	const Char *ch = &_encoding[code];
-	assert((ch->virtual_char != 0) == (ch->glyph == VIRTUAL_GLYPH));
-	for (const Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
-	    assert(valid_code(l->in2) && valid_code(l->out));
-	for (const Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
-	    assert(valid_code(k->in2));
-	if (const VirtualChar *vc = ch->virtual_char) {
-	    assert(vc->name);
-	    int font_number = 0;
-	    for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++) {
-		assert(s->valid_op());
-		if (s->op == Setting::SHOW && font_number == 0)
-		    assert(nonvirtual_code(s->x));
-		else if (s->op == Setting::FONT)
-		    font_number = s->x;
-	    }
-	}
-	assert(ch->built_in1 < 0 || valid_code(ch->built_in1));
-	assert(ch->built_in2 < 0 || valid_code(ch->built_in2));
-	assert((ch->built_in1 >= 0) == (ch->built_in2 >= 0));
-	assert(ch->base_code < 0 || valid_code(ch->base_code));
-	if (valid_code(ch->base_code)) {
-	    const Char *ch2 = &_encoding[ch->base_code];
-	    assert((!ch->virtual_char && ch->glyph)
-		   || (!ch2->virtual_char && ch2->glyph));
-	}
-	if (ch->flag(Char::CONTEXT_ONLY))
-	    assert(ch->virtual_char && ch->built_in1 >= 0 && ch->built_in2 >= 0);
-	if (ch->flag(Char::CONTEXT_ONLY))
-	    assert(ch->flag(Char::LIVE));
+        const Char *ch = &_encoding[code];
+        assert((ch->virtual_char != 0) == (ch->glyph == VIRTUAL_GLYPH));
+        for (const Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
+            assert(valid_code(l->in2) && valid_code(l->out));
+        for (const Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
+            assert(valid_code(k->in2));
+        if (const VirtualChar *vc = ch->virtual_char) {
+            assert(vc->name);
+            int font_number = 0;
+            for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++) {
+                assert(s->valid_op());
+                if (s->op == Setting::SHOW && font_number == 0)
+                    assert(nonvirtual_code(s->x));
+                else if (s->op == Setting::FONT)
+                    font_number = s->x;
+            }
+        }
+        assert(ch->built_in1 < 0 || valid_code(ch->built_in1));
+        assert(ch->built_in2 < 0 || valid_code(ch->built_in2));
+        assert((ch->built_in1 >= 0) == (ch->built_in2 >= 0));
+        assert(ch->base_code < 0 || valid_code(ch->base_code));
+        if (valid_code(ch->base_code)) {
+            const Char *ch2 = &_encoding[ch->base_code];
+            assert((!ch->virtual_char && ch->glyph)
+                   || (!ch2->virtual_char && ch2->glyph));
+        }
+        if (ch->flag(Char::CONTEXT_ONLY))
+            assert(ch->virtual_char && ch->built_in1 >= 0 && ch->built_in2 >= 0);
+        if (ch->flag(Char::CONTEXT_ONLY))
+            assert(ch->flag(Char::LIVE));
     }
 }
 
@@ -91,32 +91,32 @@ PermString
 Metrics::code_name(Code code) const
 {
     if (code < 0 || code >= _encoding.size())
-	return permprintf("<badcode%d>", code);
+        return permprintf("<badcode%d>", code);
     else {
-	const Char &ch = _encoding[code];
-	if (ch.virtual_char)
-	    return ch.virtual_char->name;
-	else if (ch.glyph == _boundary_glyph)
-	    return "<boundary>";
-	else if (ch.glyph == _emptyslot_glyph)
-	    return "<emptyslot>";
-	else if (ch.glyph >= 0 && ch.glyph < _mapped_fonts[0]->nglyphs())
-	    return _mapped_fonts[0]->glyph_name(ch.glyph);
-	else
-	    return permprintf("<glyph%d>", ch.glyph);
+        const Char &ch = _encoding[code];
+        if (ch.virtual_char)
+            return ch.virtual_char->name;
+        else if (ch.glyph == _boundary_glyph)
+            return "<boundary>";
+        else if (ch.glyph == _emptyslot_glyph)
+            return "<emptyslot>";
+        else if (ch.glyph >= 0 && ch.glyph < _mapped_fonts[0]->nglyphs())
+            return _mapped_fonts[0]->glyph_name(ch.glyph);
+        else
+            return permprintf("<glyph%d>", ch.glyph);
     }
 }
 
 
 /*****************************************************************************/
-/* encoding								     */
+/* encoding                                                                  */
 
 Metrics::Code
 Metrics::unicode_encoding(uint32_t uni) const
 {
     for (const Char *ch = _encoding.begin(); ch < _encoding.end(); ch++)
-	if (ch->unicode == uni)
-	    return ch - _encoding.begin();
+        if (ch->unicode == uni)
+            return ch - _encoding.begin();
     return -1;
 }
 
@@ -124,15 +124,15 @@ Metrics::Code
 Metrics::hard_encoding(Glyph g, Code after) const
 {
     if (g < 0)
-	return -1;
+        return -1;
     int answer = -1, n = 0;
     for (int i = _encoding.size() - 1; i >= after; i--)
-	if (_encoding[i].glyph == g)
-	    answer = i, n++;
+        if (_encoding[i].glyph == g)
+            answer = i, n++;
     if (n < 2 && after == 0) {
-	if (g >= _emap.size())
-	    _emap.resize(g + 1, -2);
-	_emap[g] = answer;
+        if (g >= _emap.size())
+            _emap.resize(g + 1, -2);
+        _emap[g] = answer;
     }
     return answer;
 }
@@ -143,15 +143,15 @@ Metrics::force_encoding(Glyph g, int loo
     assert(g >= 0);
     int e = encoding(g, 0);
     if (e >= 0)
-	return e;
+        return e;
     else {
-	Char ch;
-	ch.glyph = g;
-	ch.base_code = _encoding.size();
-	ch.lookup_source = lookup_source;
-	_encoding.push_back(ch);
-	assign_emap(g, ch.base_code);
-	return ch.base_code;
+        Char ch;
+        ch.glyph = g;
+        ch.base_code = _encoding.size();
+        ch.lookup_source = lookup_source;
+        _encoding.push_back(ch);
+        assign_emap(g, ch.base_code);
+        return ch.base_code;
     }
 }
 
@@ -160,11 +160,11 @@ Metrics::encode(Code code, uint32_t uni,
 {
     assert(code >= 0 && g >= 0 && g != VIRTUAL_GLYPH);
     if (code >= _encoding.size())
-	_encoding.resize(code + 1, Char());
+        _encoding.resize(code + 1, Char());
     _encoding[code].unicode = uni;
     _encoding[code].glyph = g;
     if (g > 0)
-	_encoding[code].base_code = code;
+        _encoding[code].base_code = code;
     assert(!_encoding[code].virtual_char);
     assign_emap(g, code);
 }
@@ -174,20 +174,20 @@ Metrics::encode_virtual(Code code, PermS
 {
     assert(code >= 0 && v.size() > 0);
     if (code >= _encoding.size())
-	_encoding.resize(code + 1, Char());
+        _encoding.resize(code + 1, Char());
     _encoding[code].unicode = uni;
     _encoding[code].glyph = VIRTUAL_GLYPH;
     if (base_char)
-	_encoding[code].flags |= Char::BASE_REP;
+        _encoding[code].flags |= Char::BASE_REP;
     assert(!_encoding[code].virtual_char);
     VirtualChar *vc = _encoding[code].virtual_char = new VirtualChar;
     vc->name = name;
     vc->setting = v;
     int font_number = 0;
     for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++) {
-	assert(s->valid_op() && (s->op != Setting::SHOW || font_number != 0 || nonvirtual_code(s->x)));
-	if (s->op == Setting::FONT)
-	    font_number = s->x;
+        assert(s->valid_op() && (s->op != Setting::SHOW || font_number != 0 || nonvirtual_code(s->x)));
+        if (s->op == Setting::FONT)
+            font_number = s->x;
     }
 }
 
@@ -196,28 +196,28 @@ Metrics::apply_base_encoding(const Strin
 {
     int font_number = -1;
     for (Char *c = _encoding.begin(); c != _encoding.end(); c++)
-	if (c->glyph > 0 && !c->virtual_char && c->glyph < mapping.size()
-	    && mapping[c->glyph] >= 0) {
-	    if (font_number < 0)
-		font_number = add_mapped_font(mapped_font(0), font_name);
-	    VirtualChar *vc = c->virtual_char = new VirtualChar;
-	    vc->name = dvipsenc.encoding(mapping[c->glyph]);
-	    vc->setting.push_back(Setting(Setting::FONT, font_number));
-	    vc->setting.push_back(Setting(Setting::SHOW, mapping[c->glyph], c->glyph));
-	    c->glyph = VIRTUAL_GLYPH;
-	    c->base_code = -1;
-	    c->flags = (c->flags & ~Char::BASE_LIVE) | Char::BASE_REP;
-	}
+        if (c->glyph > 0 && !c->virtual_char && c->glyph < mapping.size()
+            && mapping[c->glyph] >= 0) {
+            if (font_number < 0)
+                font_number = add_mapped_font(mapped_font(0), font_name);
+            VirtualChar *vc = c->virtual_char = new VirtualChar;
+            vc->name = dvipsenc.encoding(mapping[c->glyph]);
+            vc->setting.push_back(Setting(Setting::FONT, font_number));
+            vc->setting.push_back(Setting(Setting::SHOW, mapping[c->glyph], c->glyph));
+            c->glyph = VIRTUAL_GLYPH;
+            c->base_code = -1;
+            c->flags = (c->flags & ~Char::BASE_LIVE) | Char::BASE_REP;
+        }
 }
 
 void
 Metrics::add_altselector_code(Code code, int altselector_type)
 {
     for (Kern *k = _altselectors.begin(); k != _altselectors.end(); k++)
-	if (k->in2 == code) {
-	    k->kern = altselector_type;
-	    return;
-	}
+        if (k->in2 == code) {
+            k->kern = altselector_type;
+            return;
+        }
     _altselectors.push_back(Kern(code, altselector_type));
 }
 
@@ -227,16 +227,16 @@ Metrics::base_glyphs(Vector<Glyph> &v, i
     bool any = false;
     v.assign(_encoding.size(), 0);
     for (const Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
-	if (ch->base_code >= 0 && ch->base_code < size) {
-	    v[ch->base_code] = ch->glyph;
-	    any = true;
-	}
+        if (ch->base_code >= 0 && ch->base_code < size) {
+            v[ch->base_code] = ch->glyph;
+            any = true;
+        }
     return any;
 }
 
 
 /*****************************************************************************/
-/* Char methods								     */
+/* Char methods                                                              */
 
 void
 Metrics::Char::clear()
@@ -260,7 +260,7 @@ Metrics::Char::swap(Char &c)
     std::swap(glyph, c.glyph);
     // NB: only a partial switch of base_code!!
     if (base_code < 0)
-	base_code = c.base_code;
+        base_code = c.base_code;
     c.base_code = -1;
     std::swap(unicode, c.unicode);
     ligatures.swap(c.ligatures);
@@ -277,7 +277,7 @@ Metrics::Char::swap(Char &c)
 
 
 /*****************************************************************************/
-/* manipulating ligature lists						     */
+/* manipulating ligature lists                                               */
 
 Metrics::Ligature *
 Metrics::ligature_obj(Code code1, Code code2)
@@ -285,8 +285,8 @@ Metrics::ligature_obj(Code code1, Code c
     assert(valid_code(code1) && valid_code(code2));
     Char &ch = _encoding[code1];
     for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
-	if (l->in2 == code2)
-	    return l;
+        if (l->in2 == code2)
+            return l;
     return 0;
 }
 
@@ -307,39 +307,39 @@ void
 Metrics::add_ligature(Code in1, Code in2, Code out)
 {
     if (Ligature *l = ligature_obj(in1, in2)) {
-	Char &ch = _encoding[l->out];
-	if (ch.flags & Char::BUILT) {
-	    // move old ligatures to point to the true ligature
-	    for (Ligature *ll = ch.ligatures.begin(); ll != ch.ligatures.end(); ll++)
-		add_ligature(out, ll->in2, ll->out);
-	    repoint_ligature(in1, l, out);
-	}
+        Char &ch = _encoding[l->out];
+        if (ch.flags & Char::BUILT) {
+            // move old ligatures to point to the true ligature
+            for (Ligature *ll = ch.ligatures.begin(); ll != ch.ligatures.end(); ll++)
+                add_ligature(out, ll->in2, ll->out);
+            repoint_ligature(in1, l, out);
+        }
     } else
-	new_ligature(in1, in2, out);
+        new_ligature(in1, in2, out);
 }
 
 Metrics::Code
 Metrics::pair_code(Code in1, Code in2, int lookup_source)
 {
     if (const Ligature *l = ligature_obj(in1, in2)) {
-	if (lookup_source < 0)
-	    _encoding[l->out].flags &= ~Char::INTERMEDIATE;
-	return l->out;
+        if (lookup_source < 0)
+            _encoding[l->out].flags &= ~Char::INTERMEDIATE;
+        return l->out;
     } else {
-	Char ch;
-	ch.glyph = VIRTUAL_GLYPH;
-	ch.flags = Char::BUILT | (lookup_source >= 0 ? Char::INTERMEDIATE : 0);
-	VirtualChar *vc = ch.virtual_char = new VirtualChar;
-	vc->name = permprintf("%s__%s", code_str(in1), code_str(in2));
-	setting(in1, vc->setting, SET_INTERMEDIATE);
-	vc->setting.push_back(Setting(Setting::KERN));
-	setting(in2, vc->setting, SET_INTERMEDIATE);
-	ch.built_in1 = in1;
-	ch.built_in2 = in2;
-	ch.lookup_source = lookup_source;
-	_encoding.push_back(ch);
-	new_ligature(in1, in2, _encoding.size() - 1);
-	return _encoding.size() - 1;
+        Char ch;
+        ch.glyph = VIRTUAL_GLYPH;
+        ch.flags = Char::BUILT | (lookup_source >= 0 ? Char::INTERMEDIATE : 0);
+        VirtualChar *vc = ch.virtual_char = new VirtualChar;
+        vc->name = permprintf("%s__%s", code_str(in1), code_str(in2));
+        setting(in1, vc->setting, SET_INTERMEDIATE);
+        vc->setting.push_back(Setting(Setting::KERN));
+        setting(in2, vc->setting, SET_INTERMEDIATE);
+        ch.built_in1 = in1;
+        ch.built_in2 = in2;
+        ch.lookup_source = lookup_source;
+        _encoding.push_back(ch);
+        new_ligature(in1, in2, _encoding.size() - 1);
+        return _encoding.size() - 1;
     }
 }
 
@@ -347,22 +347,22 @@ void
 Metrics::remove_ligatures(Code in1, Code in2)
 {
     if (in1 == CODE_ALL) {
-	for (in1 = 0; in1 < _encoding.size(); in1++)
-	    remove_ligatures(in1, in2);
+        for (in1 = 0; in1 < _encoding.size(); in1++)
+            remove_ligatures(in1, in2);
     } else {
-	Char &ch = _encoding[in1];
-	if (in2 == CODE_ALL)
-	    ch.ligatures.clear();
-	else if (Ligature *l = ligature_obj(in1, in2)) {
-	    *l = ch.ligatures.back();
-	    ch.ligatures.pop_back();
-	}
+        Char &ch = _encoding[in1];
+        if (in2 == CODE_ALL)
+            ch.ligatures.clear();
+        else if (Ligature *l = ligature_obj(in1, in2)) {
+            *l = ch.ligatures.back();
+            ch.ligatures.pop_back();
+        }
     }
 }
 
 
 /*****************************************************************************/
-/* manipulating kern lists						     */
+/* manipulating kern lists                                                   */
 
 Metrics::Kern *
 Metrics::kern_obj(Code in1, Code in2)
@@ -370,8 +370,8 @@ Metrics::kern_obj(Code in1, Code in2)
     assert(valid_code(in1) && valid_code(in2));
     Char &ch = _encoding[in1];
     for (Kern *k = ch.kerns.begin(); k != ch.kerns.end(); k++)
-	if (k->in2 == in2)
-	    return k;
+        if (k->in2 == in2)
+            return k;
     return 0;
 }
 
@@ -381,8 +381,8 @@ Metrics::kern(Code in1, Code in2) const
     assert(valid_code(in1) && valid_code(in2));
     const Char &ch = _encoding[in1];
     for (const Kern *k = ch.kerns.begin(); k != ch.kerns.end(); k++)
-	if (k->in2 == in2)
-	    return k->kern;
+        if (k->in2 == in2)
+            return k->kern;
     return 0;
 }
 
@@ -390,30 +390,30 @@ void
 Metrics::add_kern(Code in1, Code in2, int kern)
 {
     if (Kern *k = kern_obj(in1, in2))
-	k->kern += kern;
+        k->kern += kern;
     else
-	_encoding[in1].kerns.push_back(Kern(in2, kern));
+        _encoding[in1].kerns.push_back(Kern(in2, kern));
 }
 
 void
 Metrics::set_kern(Code in1, Code in2, int kern)
 {
     if (in1 == CODE_ALL) {
-	for (in1 = 0; in1 < _encoding.size(); in1++)
-	    set_kern(in1, in2, kern);
+        for (in1 = 0; in1 < _encoding.size(); in1++)
+            set_kern(in1, in2, kern);
     } else {
-	Char &ch = _encoding[in1];
-	if (in2 == CODE_ALL) {
-	    assert(kern == 0);
-	    ch.kerns.clear();
-	} else if (Kern *k = kern_obj(in1, in2)) {
-	    if (kern == 0) {
-		*k = ch.kerns.back();
-		ch.kerns.pop_back();
-	    } else
-		k->kern = kern;
-	} else if (kern != 0)
-	    ch.kerns.push_back(Kern(in2, kern));
+        Char &ch = _encoding[in1];
+        if (in2 == CODE_ALL) {
+            assert(kern == 0);
+            ch.kerns.clear();
+        } else if (Kern *k = kern_obj(in1, in2)) {
+            if (kern == 0) {
+                *k = ch.kerns.back();
+                ch.kerns.pop_back();
+            } else
+                k->kern = kern;
+        } else if (kern != 0)
+            ch.kerns.push_back(Kern(in2, kern));
     }
 }
 
@@ -422,38 +422,38 @@ Metrics::reencode_right_ligkern(Code old
 {
     int nchanges = 0;
     for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++) {
-	for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
-	    if (l->in2 == old_in2) {
-		if (new_in2 >= 0)
-		    l->in2 = new_in2;
-		else {
-		    *l = ch->ligatures.back();
-		    ch->ligatures.pop_back();
-		    l--;
-		}
-		nchanges++;
-	    }
-	for (Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
-	    if (k->in2 == old_in2) {
-		if (new_in2 >= 0)
-		    k->in2 = new_in2;
-		else {
-		    *k = ch->kerns.back();
-		    ch->kerns.pop_back();
-		    k--;
-		}
-		nchanges++;
-	    }
-	// XXX?
-	if (ch->context_setting(-1, old_in2) && new_in2 >= 0 && ch->built_in1 >= 0)
-	    ch->built_in2 = new_in2;
+        for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
+            if (l->in2 == old_in2) {
+                if (new_in2 >= 0)
+                    l->in2 = new_in2;
+                else {
+                    *l = ch->ligatures.back();
+                    ch->ligatures.pop_back();
+                    l--;
+                }
+                nchanges++;
+            }
+        for (Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
+            if (k->in2 == old_in2) {
+                if (new_in2 >= 0)
+                    k->in2 = new_in2;
+                else {
+                    *k = ch->kerns.back();
+                    ch->kerns.pop_back();
+                    k--;
+                }
+                nchanges++;
+            }
+        // XXX?
+        if (ch->context_setting(-1, old_in2) && new_in2 >= 0 && ch->built_in1 >= 0)
+            ch->built_in2 = new_in2;
     }
     return nchanges;
 }
 
 
 /*****************************************************************************/
-/* positioning								     */
+/* positioning                                                               */
 
 void
 Metrics::add_single_positioning(Code c, int pdx, int pdy, int adx)
@@ -467,7 +467,7 @@ Metrics::add_single_positioning(Code c,
 
 
 /*****************************************************************************/
-/* changed_context structure						     */
+/* changed_context structure                                                 */
 
 class Metrics::ChangedContext { public:
     ChangedContext(int ncodes);
@@ -498,35 +498,35 @@ Metrics::ChangedContext::ChangedContext(
 Metrics::ChangedContext::~ChangedContext()
 {
     for (Vector<uint32_t> **v = _v.begin(); v != _v.end(); v++)
-	if (*v != &_all_sentinel)
-	    delete *v;
+        if (*v != &_all_sentinel)
+            delete *v;
 }
 
 inline void
 Metrics::ChangedContext::ensure_all(Code c) const
 {
     if (c >= 0 && (c >> 5) >= _all_sentinel.size())
-	_all_sentinel.resize((c >> 5) + 1, 0xFFFFFFFFU);
+        _all_sentinel.resize((c >> 5) + 1, 0xFFFFFFFFU);
 }
 
 inline bool
 Metrics::ChangedContext::bit(const Vector<uint32_t> &v, Code c)
 {
     if (c < 0 || (c >> 5) >= v.size())
-	return false;
+        return false;
     else
-	return (v[c >> 5] & (1 << (c & 0x1F))) != 0;
+        return (v[c >> 5] & (1 << (c & 0x1F))) != 0;
 }
 
 bool
 Metrics::ChangedContext::allowed(Code c, bool left_context) const
 {
     if (c < 0)
-	return false;
+        return false;
     else if (c >= _v.size())
-	return left_context;
+        return left_context;
     else
-	return (_v[c] != &_all_sentinel);
+        return (_v[c] != &_all_sentinel);
 }
 
 bool
@@ -534,11 +534,11 @@ Metrics::ChangedContext::pair_allowed(Co
 {
     ensure_all(c2);
     if (c1 < 0 || c2 < 0)
-	return false;
+        return false;
     else if (c1 >= _v.size() || c2 >= _v.size() || !_v[c1])
-	return true;
+        return true;
     else
-	return !bit(*_v[c1], c2);
+        return !bit(*_v[c1], c2);
 }
 
 bool
@@ -552,10 +552,10 @@ Metrics::ChangedContext::disallow(Code c
 {
     assert(c >= 0);
     if (c >= _v.size())
-	_v.resize(c + 1, 0);
+        _v.resize(c + 1, 0);
     if (_v[c] != &_all_sentinel) {
-	delete _v[c];
-	_v[c] = &_all_sentinel;
+        delete _v[c];
+        _v[c] = &_all_sentinel;
     }
 }
 
@@ -564,60 +564,60 @@ Metrics::ChangedContext::disallow_pair(C
 {
     assert(c1 >= 0 && c2 >= 0);
     if (c1 >= _v.size())
-	_v.resize(c1 + 1, 0);
+        _v.resize(c1 + 1, 0);
     if (!_v[c1])
-	_v[c1] = new Vector<uint32_t>;
+        _v[c1] = new Vector<uint32_t>;
     if (_v[c1] != &_all_sentinel) {
-	if ((c2 >> 5) >= _v[c1]->size())
-	    _v[c1]->resize((c2 >> 5) + 1, 0);
-	(*_v[c1])[c2 >> 5] |= 1 << (c2 & 0x1F);
+        if ((c2 >> 5) >= _v[c1]->size())
+            _v[c1]->resize((c2 >> 5) + 1, 0);
+        (*_v[c1])[c2 >> 5] |= 1 << (c2 & 0x1F);
     }
 }
 
 
 /*****************************************************************************/
-/* applying GSUB substitutions						     */
+/* applying GSUB substitutions                                               */
 
 void
 Metrics::apply_single(Code cin, const Substitution *s, int lookup,
-		ChangedContext &ctx, const GlyphFilter &glyph_filter,
-		const Vector<PermString> &glyph_names)
+                ChangedContext &ctx, const GlyphFilter &glyph_filter,
+                const Vector<PermString> &glyph_names)
 {
     // check if encoded
     if (!ctx.allowed(cin, false))
-	/* not encoded before this substitution began, or completely changed;
-	   ingore */
-	return;
+        /* not encoded before this substitution began, or completely changed;
+           ingore */
+        return;
 
     // check if substitution of this code allowed
     if (!glyph_filter.allow_substitution(s->in_glyph(), glyph_names, unicode(cin)))
-	return;
+        return;
 
     // look for an allowed alternate
     Glyph out = -1;
     for (int i = 0; out < 0 && i < s->out_nglyphs(); i++)
-	if (glyph_filter.allow_alternate(s->out_glyph(i), glyph_names, unicode(cin)))
-	    out = s->out_glyph(i);
-    if (out < 0)		// no allowed alternate
-	return;
+        if (glyph_filter.allow_alternate(s->out_glyph(i), glyph_names, unicode(cin)))
+            out = s->out_glyph(i);
+    if (out < 0)                // no allowed alternate
+        return;
 
     // apply substitution
     if (ctx.virgin(cin)) {
-	// no one has changed this glyph yet, change it unilaterally
-	assign_emap(s->in_glyph(), -2);
-	assign_emap(out, cin);
-	assert(!_encoding[cin].virtual_char);
-	_encoding[cin].glyph = out;
+        // no one has changed this glyph yet, change it unilaterally
+        assign_emap(s->in_glyph(), -2);
+        assign_emap(out, cin);
+        assert(!_encoding[cin].virtual_char);
+        _encoding[cin].glyph = out;
     } else {
-	// some contextual substitutions have changed this glyph, add
-	// contextual substitutions for the remaining possibilities
-	Code cout = force_encoding(out, lookup);
-	for (Code right = 0; right < _encoding.size(); right++)
-	    if (_encoding[right].visible() && !_encoding[right].flag(Char::BUILT) && ctx.pair_allowed(cin, right)) {
-		Code pair = pair_code(cout, right, lookup);
-		_encoding[cout].flags &= ~Char::INTERMEDIATE;
-		add_ligature(cin, right, pair);
-	    }
+        // some contextual substitutions have changed this glyph, add
+        // contextual substitutions for the remaining possibilities
+        Code cout = force_encoding(out, lookup);
+        for (Code right = 0; right < _encoding.size(); right++)
+            if (_encoding[right].visible() && !_encoding[right].flag(Char::BUILT) && ctx.pair_allowed(cin, right)) {
+                Code pair = pair_code(cout, right, lookup);
+                _encoding[cout].flags &= ~Char::INTERMEDIATE;
+                add_ligature(cin, right, pair);
+            }
     }
 
     // no more substitutions for cin
@@ -630,7 +630,7 @@ Metrics::apply_ligature(const Vector<Cod
     // build up the character pair
     int cin1 = in[0];
     for (const Code *inp = in.begin() + 1; inp < in.end() - 1; inp++)
-	cin1 = pair_code(cin1, *inp, lookup);
+        cin1 = pair_code(cin1, *inp, lookup);
     int cin2 = in.back();
 
     // build up the output character
@@ -638,18 +638,18 @@ Metrics::apply_ligature(const Vector<Cod
     s->all_out_glyphs(out);
     int cout = -1;
     for (Glyph *outp = out.begin(); outp < out.end(); outp++) {
-	*outp = force_encoding(*outp, lookup);
-	cout = (cout < 0 ? *outp : pair_code(cout, *outp, lookup));
+        *outp = force_encoding(*outp, lookup);
+        cout = (cout < 0 ? *outp : pair_code(cout, *outp, lookup));
     }
     _encoding[cout].flags &= ~Char::INTERMEDIATE;
 
     // check for replacing a fake ligature
     int old_out = -1;
     if (Ligature *l = ligature_obj(cin1, cin2)) {
-	if (l->out == cout)	// already created this same ligature
-	    return;
-	if (_encoding[l->out].flags & Char::BUILT)
-	    old_out = l->out;
+        if (l->out == cout)     // already created this same ligature
+            return;
+        if (_encoding[l->out].flags & Char::BUILT)
+            old_out = l->out;
     }
 
     // make the final ligature
@@ -659,35 +659,39 @@ Metrics::apply_ligature(const Vector<Cod
 
     // if appropriate, swap old ligatures to point to the new result
     if (old_out >= 0)
-	for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
-	    for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
-		if (l->out == old_out)
-		    repoint_ligature(ch - _encoding.begin(), l, cout);
+        for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
+            for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
+                if (l->out == old_out)
+                    repoint_ligature(ch - _encoding.begin(), l, cout);
 }
 
 void
 Metrics::apply_simple_context_ligature(const Vector<Code> &codes,
-			const Substitution *s, int lookup, ChangedContext &ctx)
+             const Substitution *s, int lookup, ChangedContext &ctx,
+             const GlyphFilter &glyph_filter,
+             const Vector<PermString>& glyph_names)
 {
     int nleft = s->left_nglyphs(), nin = s->in_nglyphs();
     assert(codes.size() >= 2);
 
     // check if context allows substitutions
-    for (const Code *inp = codes.begin(); inp < codes.end(); ++inp)
-	if (!ctx.allowed(*inp, inp - codes.begin() < nleft))
-	    return;
+    for (int i = 0; i < codes.size(); ++i) {
+        if (!ctx.allowed(codes[i], i < nleft)
+            || !glyph_filter.allow_substitution(s->in_glyph(i), glyph_names, unicode(codes[i])))
+            return;
+    }
 
     // check if any part of the combination has already changed
     int ncheck = nleft + (nin > 2 ? 2 : nin);
     if (ncheck == codes.size())
-	--ncheck;
+        --ncheck;
     for (const Code *inp = codes.begin(); inp < codes.begin() + ncheck; ++inp)
-	if (!ctx.pair_allowed(inp[0], inp[1]))
-	    return;
+        if (!ctx.pair_allowed(inp[0], inp[1]))
+            return;
 
     // mark this combination as changed if appropriate
     if (codes.size() == 2 && nin == 1)
-	ctx.disallow_pair(codes[0], codes[1]);
+        ctx.disallow_pair(codes[0], codes[1]);
 
     // actually apply ligature
     apply_ligature(codes, s, lookup);
@@ -697,18 +701,18 @@ bool
 Metrics::next_encoding(Vector<Code> &codes, const Vector<Glyph> &glyphs) const
 {
     if (!codes.size()) {
-	codes.assign(glyphs.size(), 0);
-	for (int i = 0; i < glyphs.size(); ++i)
-	    if ((codes[i] = encoding(glyphs[i], 0)) < 0)
-		return false;
-	return true;
+        codes.assign(glyphs.size(), 0);
+        for (int i = 0; i < glyphs.size(); ++i)
+            if ((codes[i] = encoding(glyphs[i], 0)) < 0)
+                return false;
+        return true;
     } else {
-	for (int i = 0; i < glyphs.size(); ++i)
-	    if ((codes[i] = encoding(glyphs[i], codes[i] + 1)) >= 0)
-		return true;
-	    else
-		codes[i] = encoding(glyphs[i], 0);
-	return false;
+        for (int i = 0; i < glyphs.size(); ++i)
+            if ((codes[i] = encoding(glyphs[i], codes[i] + 1)) >= 0)
+                return true;
+            else
+                codes[i] = encoding(glyphs[i], 0);
+        return false;
     }
 }
 
@@ -724,20 +728,20 @@ Metrics::apply(const Vector<Substitution
     // loop over substitutions
     int failures = 0;
     for (const Substitution *s = sv.begin(); s != sv.end(); s++) {
-	bool is_single = s->is_single() || s->is_alternate();
-	bool is_apply_single = is_single && allow_single;
-	bool is_apply_simple_context_ligature = !is_single && !s->is_multiple() && s->is_simple_context();
-
-	if (is_apply_single || is_apply_simple_context_ligature) {
-	    s->all_in_glyphs(glyphs);
-	    for (codes.clear(); next_encoding(codes, glyphs); ) {
-		if (is_apply_single)
-		    apply_single(codes[0], s, lookup, ctx, glyph_filter, glyph_names);
-		else
-		    apply_simple_context_ligature(codes, s, lookup, ctx);
-	    }
-	} else
-	    failures++;
+        bool is_single = s->is_single() || s->is_alternate();
+        bool is_apply_single = is_single && allow_single;
+        bool is_apply_simple_context_ligature = !is_single && !s->is_multiple() && s->is_simple_context();
+
+        if (is_apply_single || is_apply_simple_context_ligature) {
+            s->all_in_glyphs(glyphs);
+            for (codes.clear(); next_encoding(codes, glyphs); ) {
+                if (is_apply_single)
+                    apply_single(codes[0], s, lookup, ctx, glyph_filter, glyph_names);
+                else
+                    apply_simple_context_ligature(codes, s, lookup, ctx, glyph_filter, glyph_names);
+            }
+        } else
+            failures++;
     }
 
     return sv.size() - failures;
@@ -745,42 +749,42 @@ Metrics::apply(const Vector<Substitution
 
 void
 Metrics::apply_alternates_single(Code cin, const Substitution *s, int lookup,
-		const GlyphFilter &glyph_filter,
-		const Vector<PermString> &glyph_names)
+                const GlyphFilter &glyph_filter,
+                const Vector<PermString> &glyph_names)
 {
     for (const Kern *as = _altselectors.begin(); as != _altselectors.end(); as++)
-	if (as->kern == 0) {
-	    Code last = cin;
-	    uint32_t u = unicode(cin);
-	    for (int i = 0; i < s->out_nglyphs(); i++)
-		if (glyph_filter.allow_alternate(s->out_glyph(i), glyph_names, u)) {
-		    Code out = force_encoding(s->out_glyph(i), lookup);
-		    add_ligature(last, as->in2, out);
-		    last = out;
-		}
-	} else if (as->kern <= s->out_nglyphs()) {
-	    Code out = force_encoding(s->out_glyph(as->kern - 1), lookup);
-	    add_ligature(cin, as->in2, out);
-	}
+        if (as->kern == 0) {
+            Code last = cin;
+            uint32_t u = unicode(cin);
+            for (int i = 0; i < s->out_nglyphs(); i++)
+                if (glyph_filter.allow_alternate(s->out_glyph(i), glyph_names, u)) {
+                    Code out = force_encoding(s->out_glyph(i), lookup);
+                    add_ligature(last, as->in2, out);
+                    last = out;
+                }
+        } else if (as->kern <= s->out_nglyphs()) {
+            Code out = force_encoding(s->out_glyph(as->kern - 1), lookup);
+            add_ligature(cin, as->in2, out);
+        }
 }
 
 void
 Metrics::apply_alternates_ligature(const Vector<Code> &codes,
-		const Substitution *s, int lookup,
-		const GlyphFilter &glyph_filter,
-		const Vector<PermString> &glyph_names)
+                const Substitution *s, int lookup,
+                const GlyphFilter &glyph_filter,
+                const Vector<PermString> &glyph_names)
 {
     // check whether the output character is allowed
     if (!glyph_filter.allow_alternate(s->out_glyph(), glyph_names, 0))
-	return;
+        return;
 
     // find alternate selector and apply ligature if appropriate
     for (const Kern *as = _altselectors.begin(); as != _altselectors.end(); as++)
-	if (as->kern == 0) {
-	    Vector<Code> lig(codes);
-	    lig.insert(lig.begin() + 1, as->in2);
-	    apply_ligature(lig, s, lookup);
-	}
+        if (as->kern == 0) {
+            Vector<Code> lig(codes);
+            lig.insert(lig.begin() + 1, as->in2);
+            apply_ligature(lig, s, lookup);
+        }
 }
 
 void
@@ -790,36 +794,36 @@ Metrics::apply_alternates(const Vector<S
     Vector<Code> codes;
 
     for (const Substitution *s = sv.begin(); s != sv.end(); s++) {
-	bool is_single = s->is_single() || s->is_alternate();
-	if (is_single || s->is_ligature()) {
-	    s->all_in_glyphs(glyphs);
-	    for (codes.clear(); next_encoding(codes, glyphs); ) {
-		if (is_single)
-		    apply_alternates_single(codes[0], s, lookup, glyph_filter, glyph_names);
-		else
-		    apply_alternates_ligature(codes, s, lookup, glyph_filter, glyph_names);
-	    }
-	}
+        bool is_single = s->is_single() || s->is_alternate();
+        if (is_single || s->is_ligature()) {
+            s->all_in_glyphs(glyphs);
+            for (codes.clear(); next_encoding(codes, glyphs); ) {
+                if (is_single)
+                    apply_alternates_single(codes[0], s, lookup, glyph_filter, glyph_names);
+                else
+                    apply_alternates_ligature(codes, s, lookup, glyph_filter, glyph_names);
+            }
+        }
     }
 }
 
 
 /*****************************************************************************/
-/* applying GPOS positionings						     */
+/* applying GPOS positionings                                                */
 
-static bool			// returns old value
+static bool                     // returns old value
 assign_bitvec(int*& bitvec, int e, int n)
 {
     if (e >= 0 && e < n) {
-	if (!bitvec) {
-	    bitvec = new int[((n - 1) >> 5) + 1];
-	    memset(bitvec, 0, sizeof(int) * (((n - 1) >> 5) + 1));
-	}
-	bool result = (bitvec[e >> 5] & (1 << (e & 0x1F))) != 0;
-	bitvec[e >> 5] |= (1 << (e & 0x1F));
-	return result;
+        if (!bitvec) {
+            bitvec = new int[((n - 1) >> 5) + 1];
+            memset(bitvec, 0, sizeof(int) * (((n - 1) >> 5) + 1));
+        }
+        bool result = (bitvec[e >> 5] & (1 << (e & 0x1F))) != 0;
+        bitvec[e >> 5] |= (1 << (e & 0x1F));
+        return result;
     } else
-	return false;
+        return false;
 }
 
 int
@@ -834,33 +838,33 @@ Metrics::apply(const Vector<Positioning>
     // loop over substitutions
     int success = 0;
     for (const Positioning *p = pv.begin(); p != pv.end(); p++) {
-	bool is_single = p->is_single();
-	if (is_single || p->is_pairkern()) {
-	    p->all_in_glyphs(glyphs);
-	    for (codes.clear(); next_encoding(codes, glyphs); )
-		if (is_single) {
-		    if (!assign_bitvec(single_changed, codes[0], _encoding.size())) {
-			_encoding[codes[0]].pdx += p->left().pdx;
-			_encoding[codes[0]].pdy += p->left().pdy;
-			_encoding[codes[0]].adx += p->left().adx;
-		    }
-		} else {
-		    if (!assign_bitvec(pair_changed[codes[0]], codes[1], _encoding.size()))
-			add_kern(codes[0], codes[1], p->left().adx);
-		}
-	    success++;
-	}
+        bool is_single = p->is_single();
+        if (is_single || p->is_pairkern()) {
+            p->all_in_glyphs(glyphs);
+            for (codes.clear(); next_encoding(codes, glyphs); )
+                if (is_single) {
+                    if (!assign_bitvec(single_changed, codes[0], _encoding.size())) {
+                        _encoding[codes[0]].pdx += p->left().pdx;
+                        _encoding[codes[0]].pdy += p->left().pdy;
+                        _encoding[codes[0]].adx += p->left().adx;
+                    }
+                } else {
+                    if (!assign_bitvec(pair_changed[codes[0]], codes[1], _encoding.size()))
+                        add_kern(codes[0], codes[1], p->left().adx);
+                }
+            success++;
+        }
     }
 
     delete[] single_changed;
     for (int i = 0; i < pair_changed.size(); i++)
-	delete[] pair_changed[i];
+        delete[] pair_changed[i];
     return success;
 }
 
 
 /*****************************************************************************/
-/* liveness marking, Ligature3s						     */
+/* liveness marking, Ligature3s                                              */
 
 String Metrics::Ligature3::unparse(const Metrics& m) const {
     StringAccum sa;
@@ -874,11 +878,11 @@ operator<(const Metrics::Ligature3 &l1,
 {
     // topological < : is l1's output one of l2's inputs?
     if (l1.out == l2.in1 || l1.out == l2.in2)
-	return true;
+        return true;
     else
-	return l1.in1 < l2.in1
-	    || (l1.in1 == l2.in1 && (l1.in2 < l2.in2
-				     || (l1.in2 == l2.in2 && l1.out < l2.out)));
+        return l1.in1 < l2.in1
+            || (l1.in1 == l2.in1 && (l1.in2 < l2.in2
+                                     || (l1.in2 == l2.in2 && l1.out < l2.out)));
 }
 
 void
@@ -887,8 +891,8 @@ Metrics::all_ligatures(Vector<Ligature3>
     /* Develop a topologically-sorted ligature list. */
     all_ligs.clear();
     for (Code code = 0; code < _encoding.size(); code++)
-	for (const Ligature *l = _encoding[code].ligatures.begin(); l != _encoding[code].ligatures.end(); l++)
-	    all_ligs.push_back(Ligature3(code, l->in2, l->out));
+        for (const Ligature *l = _encoding[code].ligatures.begin(); l != _encoding[code].ligatures.end(); l++)
+            all_ligs.push_back(Ligature3(code, l->in2, l->out));
     std::sort(all_ligs.begin(), all_ligs.end());
 }
 
@@ -901,86 +905,86 @@ Metrics::mark_liveness(int size, const V
     // make sure we have ligatures
     Vector<Ligature3> my_ligs;
     if (!all_ligs) {
-	all_ligatures(my_ligs);
-	all_ligs = &my_ligs;
+        all_ligatures(my_ligs);
+        all_ligs = &my_ligs;
     }
 
     /* Characters below 'size' are in both virtual and base encodings. */
     for (Char *ch = _encoding.begin(); ch < _encoding.begin() + size; ch++)
-	if (ch->visible())
-	    ch->flags |= Char::LIVE | (ch->virtual_char ? 0 : Char::BASE_LIVE);
+        if (ch->visible())
+            ch->flags |= Char::LIVE | (ch->virtual_char ? 0 : Char::BASE_LIVE);
 
     /* Characters reachable from live chars by live ligatures are live. */
   redo_live_reachable:
     for (const Ligature3 *l = all_ligs->begin(); l != all_ligs->end(); l++)
-	if (_encoding[l->in1].flag(Char::LIVE) && _encoding[l->in2].flag(Char::LIVE)) {
-	    Char &ch = _encoding[l->out];
-	    if (!ch.flag(Char::LIVE))
-		ch.flags |= Char::LIVE | Char::CONTEXT_ONLY | (ch.virtual_char ? 0 : Char::BASE_LIVE);
-	    if (ch.flag(Char::CONTEXT_ONLY) && !ch.context_setting(l->in1, l->in2))
-		ch.flags &= ~Char::CONTEXT_ONLY;
-	}
+        if (_encoding[l->in1].flag(Char::LIVE) && _encoding[l->in2].flag(Char::LIVE)) {
+            Char &ch = _encoding[l->out];
+            if (!ch.flag(Char::LIVE))
+                ch.flags |= Char::LIVE | Char::CONTEXT_ONLY | (ch.virtual_char ? 0 : Char::BASE_LIVE);
+            if (ch.flag(Char::CONTEXT_ONLY) && !ch.context_setting(l->in1, l->in2))
+                ch.flags &= ~Char::CONTEXT_ONLY;
+        }
 
     /* Characters reachable from context-only ligatures are live. */
     changed = false;
     for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
-	if (ch->flag(Char::CONTEXT_ONLY)) {
-	    Char &ch1 = _encoding[ch->built_in1];
-	    Char &ch2 = _encoding[ch->built_in2];
-	    if (!ch1.flag(Char::LIVE) || !ch2.flag(Char::LIVE)) {
-		ch1.flags |= Char::LIVE;
-		ch2.flags |= Char::LIVE;
-		changed = true;
-	    }
-	}
+        if (ch->flag(Char::CONTEXT_ONLY)) {
+            Char &ch1 = _encoding[ch->built_in1];
+            Char &ch2 = _encoding[ch->built_in2];
+            if (!ch1.flag(Char::LIVE) || !ch2.flag(Char::LIVE)) {
+                ch1.flags |= Char::LIVE;
+                ch2.flags |= Char::LIVE;
+                changed = true;
+            }
+        }
     if (changed)
-	goto redo_live_reachable;
+        goto redo_live_reachable;
 
     /* Characters reachable from live settings are base-live. */
     for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
-	if (ch->flag(Char::LIVE))
-	    if (VirtualChar *vc = ch->virtual_char) {
-		int font_number = 0;
-		for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
-		    if (s->op == Setting::SHOW && font_number == 0
-			&& _encoding[s->x].base_code >= 0)
-			_encoding[s->x].flags |= Char::BASE_LIVE;
-		    else if (s->op == Setting::FONT)
-			font_number = s->x;
-	    }
+        if (ch->flag(Char::LIVE))
+            if (VirtualChar *vc = ch->virtual_char) {
+                int font_number = 0;
+                for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
+                    if (s->op == Setting::SHOW && font_number == 0
+                        && _encoding[s->x].base_code >= 0)
+                        _encoding[s->x].flags |= Char::BASE_LIVE;
+                    else if (s->op == Setting::FONT)
+                        font_number = s->x;
+            }
 }
 
 void
 Metrics::reencode(const Vector<Code> &reencoding)
 {
     for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++) {
-	for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++) {
-	    l->in2 = reencoding[l->in2];
-	    l->out = reencoding[l->out];
-	}
-	for (Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
-	    k->in2 = reencoding[k->in2];
-	if (VirtualChar *vc = ch->virtual_char) {
-	    int font_number = 0;
-	    for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
-		if (s->op == Setting::SHOW && font_number == 0)
-		    s->x = reencoding[s->x];
-		else if (s->op == Setting::FONT)
-		    font_number = s->x;
-	}
-	if (ch->built_in1 >= 0) {
-	    ch->built_in1 = reencoding[ch->built_in1];
-	    ch->built_in2 = reencoding[ch->built_in2];
-	}
-	if (ch->base_code >= 0)
-	    ch->base_code = reencoding[ch->base_code];
+        for (Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++) {
+            l->in2 = reencoding[l->in2];
+            l->out = reencoding[l->out];
+        }
+        for (Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
+            k->in2 = reencoding[k->in2];
+        if (VirtualChar *vc = ch->virtual_char) {
+            int font_number = 0;
+            for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
+                if (s->op == Setting::SHOW && font_number == 0)
+                    s->x = reencoding[s->x];
+                else if (s->op == Setting::FONT)
+                    font_number = s->x;
+        }
+        if (ch->built_in1 >= 0) {
+            ch->built_in1 = reencoding[ch->built_in1];
+            ch->built_in2 = reencoding[ch->built_in2];
+        }
+        if (ch->base_code >= 0)
+            ch->base_code = reencoding[ch->base_code];
     }
     _emap.clear();
 }
 
 
 /*****************************************************************************/
-/* shrinking the encoding						     */
+/* shrinking the encoding                                                    */
 
 bool
 Metrics::Char::context_setting(Code in1, Code in2) const
@@ -988,9 +992,9 @@ Metrics::Char::context_setting(Code in1,
     // return true iff this character could represent the context setting of
     // 'in1' and 'in2'
     if (!virtual_char || ligatures.size())
-	return false;
+        return false;
     else
-	return (in1 == built_in1 || in2 == built_in2);
+        return (in1 == built_in1 || in2 == built_in2);
 }
 
 void
@@ -1001,56 +1005,56 @@ Metrics::cut_encoding(int size)
 
     /* Change "emptyslot"s to ".notdef"s. */
     for (Char *ch = _encoding.begin(); ch != _encoding.end(); ch++)
-	if (ch->glyph == emptyslot_glyph()) {
-	    ch->glyph = 0;
-	    ch->base_code = -1;
-	    // 21.Feb.2007: Character isn't live any more.
-	    ch->flags &= ~(Char::BASE_LIVE | Char::LIVE);
-	}
+        if (ch->glyph == emptyslot_glyph()) {
+            ch->glyph = 0;
+            ch->base_code = -1;
+            // 21.Feb.2007: Character isn't live any more.
+            ch->flags &= ~(Char::BASE_LIVE | Char::LIVE);
+        }
 
     /* Maybe we don't need to do anything else. */
     if (_encoding.size() <= size) {
-	_encoding.resize(size, Char());
-	return;
+        _encoding.resize(size, Char());
+        return;
     }
 
     /* Need liveness markings. */
     if (!_liveness_marked)
-	mark_liveness(size);
+        mark_liveness(size);
 
     /* Characters below 'size' are 'good'.
        Characters above 'size' are not 'good'. */
     Vector<int> good(_encoding.size(), 1);
     for (Code c = size; c < _encoding.size(); c++)
-	good[c] = 0;
+        good[c] = 0;
 
     /* Characters encoded via base_code are 'good', though. */
     for (Char *ch = _encoding.begin(); ch < _encoding.begin() + size; ch++)
-	if (ch->base_code >= size)
-	    good[ch->base_code] = 1;
+        if (ch->base_code >= size)
+            good[ch->base_code] = 1;
 
     /* Some fake characters might point beyond 'size'; remove them too. No
        need for a multipass algorithm since virtual chars never point to
        virtual chars. */
     for (Code c = 0; c < _encoding.size(); c++) {
-	if (VirtualChar *vc = _encoding[c].virtual_char) {
-	    int font_number = 0;
-	    for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
-		if (s->op == Setting::SHOW && font_number == 0 && !good[s->x]) {
-		    _encoding[c].clear();
-		    goto bad_virtual_char;
-		} else if (s->op == Setting::FONT)
-		    font_number = s->x;
-	}
-	if (c < size)
-	    good[c] = 1;
+        if (VirtualChar *vc = _encoding[c].virtual_char) {
+            int font_number = 0;
+            for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
+                if (s->op == Setting::SHOW && font_number == 0 && !good[s->x]) {
+                    _encoding[c].clear();
+                    goto bad_virtual_char;
+                } else if (s->op == Setting::FONT)
+                    font_number = s->x;
+        }
+        if (c < size)
+            good[c] = 1;
       bad_virtual_char: ;
     }
 
     /* Certainly none of the later ligatures or kerns will be meaningful. */
     for (Code c = size; c < _encoding.size(); c++) {
-	_encoding[c].ligatures.clear();
-	_encoding[c].kerns.clear();
+        _encoding[c].ligatures.clear();
+        _encoding[c].kerns.clear();
     }
 
     /* Remove ligatures and kerns that point beyond 'size', except for valid
@@ -1059,20 +1063,20 @@ Metrics::cut_encoding(int size)
     /* 30.May.2005 -- Kerns might point involve a too-high character; kill
        them. */
     for (Code c = 0; c < size; c++) {
-	Char &ch = _encoding[c];
-	for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
-	    if (!good[l->in2] || l->in2 >= size
-		|| (!good[l->out] && !_encoding[l->out].context_setting(c, l->in2))) {
-		*l = ch.ligatures.back();
-		ch.ligatures.pop_back();
-		l--;
-	    }
-	for (Kern *k = ch.kerns.begin(); k != ch.kerns.end(); k++)
-	    if (!good[k->in2] || k->in2 >= size) {
-		*k = ch.kerns.back();
-		ch.kerns.pop_back();
-		k--;
-	    }
+        Char &ch = _encoding[c];
+        for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
+            if (!good[l->in2] || l->in2 >= size
+                || (!good[l->out] && !_encoding[l->out].context_setting(c, l->in2))) {
+                *l = ch.ligatures.back();
+                ch.ligatures.pop_back();
+                l--;
+            }
+        for (Kern *k = ch.kerns.begin(); k != ch.kerns.end(); k++)
+            if (!good[k->in2] || k->in2 >= size) {
+                *k = ch.kerns.back();
+                ch.kerns.pop_back();
+                k--;
+            }
     }
 
     /* We are done! */
@@ -1097,19 +1101,19 @@ static int
 unicode_score(uint32_t u)
 {
     if (u == 0)
-	return NOCHAR_SCORE;
+        return NOCHAR_SCORE;
     else if (u >= 'a' && u <= 'z')
-	return BASIC_LATIN_LOWER_SCORE;
+        return BASIC_LATIN_LOWER_SCORE;
     else if (u >= 'A' && u <= 'Z')
-	return BASIC_LATIN_UPPER_SCORE;
+        return BASIC_LATIN_UPPER_SCORE;
     else if (u < 0x0080)
-	return BASIC_LATIN_OTHER_SCORE;
+        return BASIC_LATIN_OTHER_SCORE;
     else if (u < 0x0100)
-	return LATIN1_SUPPLEMENT_SCORE;
+        return LATIN1_SUPPLEMENT_SCORE;
     else if (u < 0x8000)
-	return LOW_16_SCORE;
+        return LOW_16_SCORE;
     else
-	return OTHER_SCORE;
+        return OTHER_SCORE;
 }
 
 struct Slot {
@@ -1145,8 +1149,8 @@ Metrics::shrink_encoding(int size, const
 
     /* Maybe we don't need to do anything. */
     if (_encoding.size() <= size) {
-	cut_encoding(size);
-	return;
+        cut_encoding(size);
+        return;
     }
 
     /* Need a list of all ligatures.. */
@@ -1155,7 +1159,7 @@ Metrics::shrink_encoding(int size, const
 
     /* Need liveness markings. */
     if (!_liveness_marked)
-	mark_liveness(size, &all_ligs);
+        mark_liveness(size, &all_ligs);
 
     /* Score characters by importance. Importance relates first to Unicode
        values, and then recursively to the importances of characters that form
@@ -1164,8 +1168,8 @@ Metrics::shrink_encoding(int size, const
     /* Create an initial set of scores, based on Unicode values. */
     Vector<int> scores(_encoding.size(), NOCHAR_SCORE);
     for (int i = 0; i < _encoding.size(); i++)
-	if (_encoding[i].unicode)
-	    scores[i] = unicode_score(_encoding[i].unicode);
+        if (_encoding[i].unicode)
+            scores[i] = unicode_score(_encoding[i].unicode);
 
     /* Prefer conventional f-ligatures. */
     bool has_ff = false;
@@ -1194,121 +1198,121 @@ Metrics::shrink_encoding(int size, const
        only by fakes. */
     bool changed = true;
     while (changed) {
-	changed = false;
-	for (Ligature3 *l = all_ligs.begin(); l != all_ligs.end(); l++) {
-	    int score = scores[l->in1] + scores[l->in2];
-	    if (scores[l->out] > score)
+        changed = false;
+        for (Ligature3 *l = all_ligs.begin(); l != all_ligs.end(); l++) {
+            int score = scores[l->in1] + scores[l->in2];
+            if (scores[l->out] > score)
                 scores[l->out] = score, changed = true;
-	}
+        }
 
-	for (Code c = 0; c < _encoding.size(); c++)
-	    if (VirtualChar *vc = _encoding[c].virtual_char) {
-		/* Make sure that if this virtual character appears, its parts
-		   will also appear, by scoring the parts less */
-		int score = scores[c] - 1, font_number = 0;
-		for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
-		    if (s->op == Setting::SHOW && font_number == 0
-			&& score < scores[s->x])
-			scores[s->x] = score, changed = true;
-		    else if (s->op == Setting::FONT)
-			font_number = s->x;
-	    }
+        for (Code c = 0; c < _encoding.size(); c++)
+            if (VirtualChar *vc = _encoding[c].virtual_char) {
+                /* Make sure that if this virtual character appears, its parts
+                   will also appear, by scoring the parts less */
+                int score = scores[c] - 1, font_number = 0;
+                for (Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
+                    if (s->op == Setting::SHOW && font_number == 0
+                        && score < scores[s->x])
+                        scores[s->x] = score, changed = true;
+                    else if (s->op == Setting::FONT)
+                        font_number = s->x;
+            }
     }
 
     /* Rescore intermediates to not be better off than their endpoints. */
     /* XXX multiple layers of intermediate? */
     for (Code c = 0; c < _encoding.size(); c++) {
-	Char &ch = _encoding[c];
-	if (ch.flag(Char::INTERMEDIATE))
-	    for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
-		if (scores[c] < scores[l->out] && !_encoding[l->out].context_setting(c, l->in2))
-		    scores[c] = scores[l->out];
+        Char &ch = _encoding[c];
+        if (ch.flag(Char::INTERMEDIATE))
+            for (Ligature *l = ch.ligatures.begin(); l != ch.ligatures.end(); l++)
+                if (scores[c] < scores[l->out] && !_encoding[l->out].context_setting(c, l->in2))
+                    scores[c] = scores[l->out];
     }
 
     /* Collect characters that want to be reassigned. */
     Vector<Slot> slots;
     for (Code c = size; c < _encoding.size(); c++)
-	if (scores[c] < NOCHAR_SCORE
-	    && !(_encoding[c].flags & Char::CONTEXT_ONLY)
-	    && (_encoding[c].flags & (Char::LIVE | Char::BASE_LIVE))) {
-	    Slot slot = { c, -1, _encoding[c].glyph, scores[c], _encoding[c].lookup_source };
-	    slots.push_back(slot);
-	}
+        if (scores[c] < NOCHAR_SCORE
+            && !(_encoding[c].flags & Char::CONTEXT_ONLY)
+            && (_encoding[c].flags & (Char::LIVE | Char::BASE_LIVE))) {
+            Slot slot = { c, -1, _encoding[c].glyph, scores[c], _encoding[c].lookup_source };
+            slots.push_back(slot);
+        }
     // Sort them by score, then by glyph.
     std::sort(slots.begin(), slots.end());
 
     /* Prefer their old slots, if available. */
     for (Slot *slot = slots.begin(); slot < slots.end(); slot++)
-	if (PermString g = code_name(slot->old_code)) {
-	    int c = dvipsenc.encoding_of(g);
-	    if (c >= 0 && _encoding[c].glyph == 0) {
-		_encoding[c].swap(_encoding[slot->old_code]);
-		slot->new_code = c;
-	    }
-	}
+        if (PermString g = code_name(slot->old_code)) {
+            int c = dvipsenc.encoding_of(g);
+            if (c >= 0 && _encoding[c].glyph == 0) {
+                _encoding[c].swap(_encoding[slot->old_code]);
+                slot->new_code = c;
+            }
+        }
 
     /* List empty slots in two phases: Those not encoded by the input
        encoding, then those encoded by the input encoding (but that character
        wasn't available). */
     Vector<Code> empty_codes;
     for (int want_encoded = 0; want_encoded < 2; want_encoded++)
-	for (Code c = 0; c < size; c++)
-	    if (_encoding[c].base_code < 0
-		&& dvipsenc.encoded(c) == (bool) want_encoded)
-		empty_codes.push_back(c);
+        for (Code c = 0; c < size; c++)
+            if (_encoding[c].base_code < 0
+                && dvipsenc.encoded(c) == (bool) want_encoded)
+                empty_codes.push_back(c);
 
     /* Then, assign codes to the unencoded characters. */
     int nunencoded = 0;
 
     for (Slot *slot = slots.begin(); slot != slots.end(); slot++) {
-	if (slot->new_code >= 0)
-	    continue;
+        if (slot->new_code >= 0)
+            continue;
 
-	int needs = (_encoding[slot->old_code].visible_base() ? 1 : 0)
-	    + (_encoding[slot->old_code].flag(Char::LIVE) ? 2 : 0);
-	assert(needs > 0);
-
-	Code dest = -1;
-	for (Code *h = empty_codes.begin(); h < empty_codes.end() && dest < 0; h++) {
-	    int haves = (_encoding[*h].base_code < 0 ? 1 : 0)
-		+ (!_encoding[*h].visible() ? 2 : 0);
-	    if ((needs & haves) == needs)
-		dest = *h;
-	}
-
-	if (dest >= 0) {
-	    if (needs & 2) {
-		assert(!_encoding[dest].visible());
-		_encoding[dest].swap(_encoding[slot->old_code]);
-		slot->new_code = dest;
-	    } else {
-		_encoding[slot->old_code].base_code = dest;
-		slot->new_code = slot->old_code;
-	    }
-	    if (needs & 1) {
-		assert(_encoding[dest].base_code < 0 || _encoding[dest].base_code == slot->old_code);
-		_encoding[dest].base_code = slot->old_code;
-	    }
-	} else
-	    nunencoded++;
+        int needs = (_encoding[slot->old_code].visible_base() ? 1 : 0)
+            + (_encoding[slot->old_code].flag(Char::LIVE) ? 2 : 0);
+        assert(needs > 0);
+
+        Code dest = -1;
+        for (Code *h = empty_codes.begin(); h < empty_codes.end() && dest < 0; h++) {
+            int haves = (_encoding[*h].base_code < 0 ? 1 : 0)
+                + (!_encoding[*h].visible() ? 2 : 0);
+            if ((needs & haves) == needs)
+                dest = *h;
+        }
+
+        if (dest >= 0) {
+            if (needs & 2) {
+                assert(!_encoding[dest].visible());
+                _encoding[dest].swap(_encoding[slot->old_code]);
+                slot->new_code = dest;
+            } else {
+                _encoding[slot->old_code].base_code = dest;
+                slot->new_code = slot->old_code;
+            }
+            if (needs & 1) {
+                assert(_encoding[dest].base_code < 0 || _encoding[dest].base_code == slot->old_code);
+                _encoding[dest].base_code = slot->old_code;
+            }
+        } else
+            nunencoded++;
     }
 
     /* Complain if some characters can't fit. */
     if (nunencoded) {
-	// collect names of unencoded glyphs
-	Vector<String> unencoded;
-	for (Slot *slot = slots.begin(); slot != slots.end(); slot++)
-	    if (slot->new_code < 0)
-		unencoded.push_back(code_name(slot->old_code));
-	std::sort(unencoded.begin(), unencoded.end());
-	StringAccum sa;
-	for (const String* a = unencoded.begin(); a < unencoded.end(); a++)
-	    sa << *a << ' ';
-	sa.pop_back();
-	sa.append_break_lines(sa.take_string(), 68, "  ");
-	sa.pop_back();
-	errh->lwarning(" ", (unencoded.size() == 1 ? "not enough room in encoding, ignoring %d glyph" : "not enough room in encoding, ignoring %d glyphs"), unencoded.size());
-	errh->lmessage(" ", "(\
+        // collect names of unencoded glyphs
+        Vector<String> unencoded;
+        for (Slot *slot = slots.begin(); slot != slots.end(); slot++)
+            if (slot->new_code < 0)
+                unencoded.push_back(code_name(slot->old_code));
+        std::sort(unencoded.begin(), unencoded.end());
+        StringAccum sa;
+        for (const String* a = unencoded.begin(); a < unencoded.end(); a++)
+            sa << *a << ' ';
+        sa.pop_back();
+        sa.append_break_lines(sa.take_string(), 68, "  ");
+        sa.pop_back();
+        errh->lwarning(" ", (unencoded.size() == 1 ? "not enough room in encoding, ignoring %d glyph" : "not enough room in encoding, ignoring %d glyphs"), unencoded.size());
+        errh->lmessage(" ", "(\
 The font uses more glyphs than the encoding has available slots,\n\
 so these glyphs have been left out:\n%s\n\
 To select specific glyphs, add them to the input encoding.)", sa.c_str());
@@ -1317,10 +1321,10 @@ To select specific glyphs, add them to t
     /* Reencode changed slots. */
     Vector<Code> reencoding;
     for (Code c = 0; c < _encoding.size(); c++)
-	reencoding.push_back(c);
+        reencoding.push_back(c);
     for (Slot *s = slots.begin(); s != slots.end(); s++)
-	if (s->new_code >= 0)
-	    reencoding[s->old_code] = s->new_code;
+        if (s->new_code >= 0)
+            reencoding[s->old_code] = s->new_code;
     reencode(reencoding);
 
     check();
@@ -1331,38 +1335,38 @@ Metrics::make_base(int size)
 {
     Vector<Code> reencoding;
     for (Code c = 0; c < size && c < _encoding.size(); c++) {
-	Char &ch = _encoding[c];
-	if (ch.base_code >= 0 && ch.base_code != c) {
-	    if (!reencoding.size())
-		for (Code cc = 0; cc < _encoding.size(); cc++)
-		    reencoding.push_back(cc);
-	    reencoding[ch.base_code] = c;
-	    reencoding[c] = ch.base_code;
-	    _encoding[c].swap(_encoding[ch.base_code]);
-	}
-	if (ch.virtual_char)	// remove it
-	    ch.clear();
+        Char &ch = _encoding[c];
+        if (ch.base_code >= 0 && ch.base_code != c) {
+            if (!reencoding.size())
+                for (Code cc = 0; cc < _encoding.size(); cc++)
+                    reencoding.push_back(cc);
+            reencoding[ch.base_code] = c;
+            reencoding[c] = ch.base_code;
+            _encoding[c].swap(_encoding[ch.base_code]);
+        }
+        if (ch.virtual_char)    // remove it
+            ch.clear();
     }
     if (reencoding.size()) {
-	reencode(reencoding);
-	cut_encoding(size);
+        reencode(reencoding);
+        cut_encoding(size);
     }
     check();
 }
 
 
 /*****************************************************************************/
-/* output								     */
+/* output                                                                    */
 
 bool
 Metrics::need_virtual(int size) const
 {
     if (size > _encoding.size())
-	size = _encoding.size();
+        size = _encoding.size();
     for (const Char *ch = _encoding.begin(); ch < _encoding.begin() + size; ch++)
-	if (ch->glyph /* actually encoded */
-	    && (ch->pdx || ch->pdy || ch->adx || ch->virtual_char))
-	    return true;
+        if (ch->glyph /* actually encoded */
+            && (ch->pdx || ch->pdy || ch->adx || ch->virtual_char))
+            return true;
     return false;
 }
 
@@ -1370,10 +1374,10 @@ bool
 Metrics::need_base()
 {
     if (!_liveness_marked)
-	mark_liveness(_encoding.size());
+        mark_liveness(_encoding.size());
     for (const Char *ch = _encoding.begin(); ch < _encoding.end(); ch++)
-	if ((ch->flags & Char::BASE_LIVE) && ch->glyph != _boundary_glyph)
-	    return true;
+        if ((ch->flags & Char::BASE_LIVE) && ch->glyph != _boundary_glyph)
+            return true;
     return false;
 }
 
@@ -1383,72 +1387,72 @@ Metrics::setting(Code code, Vector<Setti
     extern int letterspace;
 
     if (!(sm & SET_KEEP))
-	v.clear();
+        v.clear();
 
     if (!valid_code(code) || _encoding[code].glyph == 0)
-	return false;
+        return false;
 
     const Char &ch = _encoding[code];
 
     if (const VirtualChar *vc = ch.virtual_char) {
-	bool good = true;
-	int font_number = 0;
+        bool good = true;
+        int font_number = 0;
 
-	if (ch.pdx != 0 || ch.pdy != 0)
-	    v.push_back(Setting(Setting::MOVE, ch.pdx, ch.pdy));
+        if (ch.pdx != 0 || ch.pdy != 0)
+            v.push_back(Setting(Setting::MOVE, ch.pdx, ch.pdy));
 
-	for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
-	    switch (s->op) {
-	      case Setting::MOVE:
-	      case Setting::RULE:
-	      case Setting::PUSH:
-	      case Setting::POP:
-	      case Setting::SPECIAL:
-		v.push_back(*s);
-		break;
-	      case Setting::FONT:
-		v.push_back(*s);
-		font_number = s->x;
-		break;
-	      case Setting::SHOW:
-		if (font_number == 0)
-		    good &= setting(s->x, v, (SettingMode)(sm | SET_KEEP));
-		else
-		    v.push_back(*s);
-		break;
-	      case Setting::KERN:
-	      case Setting::KERNX:
-		if (sm & SET_INTERMEDIATE)
-		    v.push_back(*s);
-		else if (font_number == 0 && s > vc->setting.begin()
-			 && s + 1 < vc->setting.end()
-			 && s[-1].op == Setting::SHOW
-			 && s[1].op == Setting::SHOW) {
-		    int k = kern(s[-1].x, s[1].x);
-		    if (s->op == Setting::KERNX)
-			k -= letterspace;
-		    if (k)
-			v.push_back(Setting(Setting::MOVE, k, 0));
-		}
-		break;
-	    }
-
-	if (ch.pdy != 0 || ch.adx - ch.pdx != 0)
-	    v.push_back(Setting(Setting::MOVE, ch.adx - ch.pdx, -ch.pdy));
-	return good;
+        for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
+            switch (s->op) {
+              case Setting::MOVE:
+              case Setting::RULE:
+              case Setting::PUSH:
+              case Setting::POP:
+              case Setting::SPECIAL:
+                v.push_back(*s);
+                break;
+              case Setting::FONT:
+                v.push_back(*s);
+                font_number = s->x;
+                break;
+              case Setting::SHOW:
+                if (font_number == 0)
+                    good &= setting(s->x, v, (SettingMode)(sm | SET_KEEP));
+                else
+                    v.push_back(*s);
+                break;
+              case Setting::KERN:
+              case Setting::KERNX:
+                if (sm & SET_INTERMEDIATE)
+                    v.push_back(*s);
+                else if (font_number == 0 && s > vc->setting.begin()
+                         && s + 1 < vc->setting.end()
+                         && s[-1].op == Setting::SHOW
+                         && s[1].op == Setting::SHOW) {
+                    int k = kern(s[-1].x, s[1].x);
+                    if (s->op == Setting::KERNX)
+                        k -= letterspace;
+                    if (k)
+                        v.push_back(Setting(Setting::MOVE, k, 0));
+                }
+                break;
+            }
+
+        if (ch.pdy != 0 || ch.adx - ch.pdx != 0)
+            v.push_back(Setting(Setting::MOVE, ch.adx - ch.pdx, -ch.pdy));
+        return good;
 
     } else if (ch.base_code >= 0) {
-	if (ch.pdx != 0 || ch.pdy != 0)
-	    v.push_back(Setting(Setting::MOVE, ch.pdx, ch.pdy));
+        if (ch.pdx != 0 || ch.pdy != 0)
+            v.push_back(Setting(Setting::MOVE, ch.pdx, ch.pdy));
 
-	v.push_back(Setting(Setting::SHOW, ch.base_code, ch.glyph));
+        v.push_back(Setting(Setting::SHOW, ch.base_code, ch.glyph));
 
-	if (ch.pdy != 0 || ch.adx - ch.pdx != 0)
-	    v.push_back(Setting(Setting::MOVE, ch.adx - ch.pdx, -ch.pdy));
-	return true;
+        if (ch.pdy != 0 || ch.adx - ch.pdx != 0)
+            v.push_back(Setting(Setting::MOVE, ch.adx - ch.pdx, -ch.pdy));
+        return true;
 
     } else
-	return false;
+        return false;
 }
 
 int
@@ -1460,22 +1464,22 @@ Metrics::ligatures(Code in1, Vector<Code
 
     const Char &in1ch = _encoding[in1];
     for (const Ligature *l = in1ch.ligatures.begin(); l != in1ch.ligatures.end(); l++) {
-	in2.push_back(l->in2);
-	const Char &outch = _encoding[l->out];
-	if (outch.context_setting(in1, l->in2)) {
-	    if (in1 == outch.built_in1 && l->in2 == outch.built_in2)
-		in2.pop_back();
-	    else if (in1 == outch.built_in1) {
-		out.push_back(outch.built_in2);
-		context.push_back(-1);
-	    } else {
-		out.push_back(outch.built_in1);
-		context.push_back(1);
-	    }
-	} else {
-	    out.push_back(l->out);
-	    context.push_back(0);
-	}
+        in2.push_back(l->in2);
+        const Char &outch = _encoding[l->out];
+        if (outch.context_setting(in1, l->in2)) {
+            if (in1 == outch.built_in1 && l->in2 == outch.built_in2)
+                in2.pop_back();
+            else if (in1 == outch.built_in1) {
+                out.push_back(outch.built_in2);
+                context.push_back(-1);
+            } else {
+                out.push_back(outch.built_in1);
+                context.push_back(1);
+            }
+        } else {
+            out.push_back(l->out);
+            context.push_back(0);
+        }
     }
 
     return in2.size();
@@ -1489,74 +1493,74 @@ Metrics::kerns(Code in1, Vector<Code> &i
 
     const Char &in1ch = _encoding[in1];
     for (const Kern *k = in1ch.kerns.begin(); k != in1ch.kerns.end(); k++)
-	if (k->kern != 0) {
-	    in2.push_back(k->in2);
-	    kern.push_back(k->kern);
-	}
+        if (k->kern != 0) {
+            in2.push_back(k->in2);
+            kern.push_back(k->kern);
+        }
 
     return in2.size();
 }
 
 
 /*****************************************************************************/
-/* debugging								     */
+/* debugging                                                                 */
 
 void
 Metrics::unparse(const Char *ch) const
 {
     Code c;
     if (ch >= _encoding.begin() && ch < _encoding.end())
-	c = ch - _encoding.begin();
+        c = ch - _encoding.begin();
     else
-	c = -1;
+        c = -1;
     fprintf(stderr, "%4d/%s%s%s%s%s%s\n", c, code_str(c),
-	    (ch->flag(Char::LIVE) ? " [L]" : ""),
-	    (ch->flag(Char::BASE_LIVE) ? " [B]" : ""),
-	    (ch->flag(Char::CONTEXT_ONLY) ? " [C]" : ""),
-	    (ch->flag(Char::BUILT) ? " [!]" : ""),
-	    (ch->base_code >= 0 ? " <BC>" : ""));
+            (ch->flag(Char::LIVE) ? " [L]" : ""),
+            (ch->flag(Char::BASE_LIVE) ? " [B]" : ""),
+            (ch->flag(Char::CONTEXT_ONLY) ? " [C]" : ""),
+            (ch->flag(Char::BUILT) ? " [!]" : ""),
+            (ch->base_code >= 0 ? " <BC>" : ""));
     if (ch->base_code >= 0 && ch->base_code != c)
-	fprintf(stderr, "\tBASE %d/%s\n", ch->base_code, code_str(ch->base_code));
+        fprintf(stderr, "\tBASE %d/%s\n", ch->base_code, code_str(ch->base_code));
     if (const VirtualChar *vc = ch->virtual_char) {
-	fprintf(stderr, "\t*");
-	int curfont = 0;
-	for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
-	    switch (s->op) {
-	      case Setting::FONT:
-		fprintf(stderr, " {F%d}", s->x);
-		curfont = s->x;
-		break;
-	      case Setting::SHOW:
-		fprintf(stderr, " %d", s->x);
-		if (curfont == 0)
-		    fprintf(stderr, "/%s", code_str(s->x));
-		break;
-	      case Setting::KERN:
-		fprintf(stderr, " <>");
-		break;
-	      case Setting::MOVE:
-		fprintf(stderr, " <%+d,%+d>", s->x, s->y);
-		break;
-	      case Setting::RULE:
-		fprintf(stderr, " [%d,%d]", s->x, s->y);
-		break;
-	      case Setting::PUSH:
-		fprintf(stderr, " (");
-		break;
-	      case Setting::POP:
-		fprintf(stderr, " )");
-		break;
-	      case Setting::SPECIAL:
-		fprintf(stderr, " S{%s}", s->s.c_str());
-		break;
-	    }
-	fprintf(stderr, "  ((%d/%s, %d/%s))\n", ch->built_in1, code_str(ch->built_in1), ch->built_in2, code_str(ch->built_in2));
+        fprintf(stderr, "\t*");
+        int curfont = 0;
+        for (const Setting *s = vc->setting.begin(); s != vc->setting.end(); s++)
+            switch (s->op) {
+              case Setting::FONT:
+                fprintf(stderr, " {F%d}", s->x);
+                curfont = s->x;
+                break;
+              case Setting::SHOW:
+                fprintf(stderr, " %d", s->x);
+                if (curfont == 0)
+                    fprintf(stderr, "/%s", code_str(s->x));
+                break;
+              case Setting::KERN:
+                fprintf(stderr, " <>");
+                break;
+              case Setting::MOVE:
+                fprintf(stderr, " <%+d,%+d>", s->x, s->y);
+                break;
+              case Setting::RULE:
+                fprintf(stderr, " [%d,%d]", s->x, s->y);
+                break;
+              case Setting::PUSH:
+                fprintf(stderr, " (");
+                break;
+              case Setting::POP:
+                fprintf(stderr, " )");
+                break;
+              case Setting::SPECIAL:
+                fprintf(stderr, " S{%s}", s->s.c_str());
+                break;
+            }
+        fprintf(stderr, "  ((%d/%s, %d/%s))\n", ch->built_in1, code_str(ch->built_in1), ch->built_in2, code_str(ch->built_in2));
     }
     for (const Ligature *l = ch->ligatures.begin(); l != ch->ligatures.end(); l++)
-	fprintf(stderr, "\t[%d/%s => %d/%s]%s\n", l->in2, code_str(l->in2), l->out, code_str(l->out), (_encoding[l->out].context_setting(c, l->in2) ? " [C]" : ""));
+        fprintf(stderr, "\t[%d/%s => %d/%s]%s\n", l->in2, code_str(l->in2), l->out, code_str(l->out), (_encoding[l->out].context_setting(c, l->in2) ? " [C]" : ""));
 #if 0
     for (const Kern *k = ch->kerns.begin(); k != ch->kerns.end(); k++)
-	fprintf(stderr, "\t{%d/%s %+d}\n", k->in2, code_str(k->in2), k->kern);
+        fprintf(stderr, "\t{%d/%s %+d}\n", k->in2, code_str(k->in2), k->kern);
 #endif
 }
 
@@ -1564,6 +1568,6 @@ void
 Metrics::unparse() const
 {
     for (const Char *ch = _encoding.begin(); ch < _encoding.end(); ch++)
-	if (ch->glyph)
-	    unparse(ch);
+        if (ch->glyph)
+            unparse(ch);
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/metrics.hh	2018-02-23 12:47:54.092971728 -0500
@@ -2,23 +2,11 @@
 #define OTFTOTFM_METRICS_HH
 #include <efont/otfgsub.hh>
 #include <efont/otfgpos.hh>
+#include "setting.hh"
 namespace Efont { class CharstringProgram; }
 class DvipsEncoding;
 class GlyphFilter;
 
-struct Setting {
-    enum { NONE, FONT, SHOW, KERN, KERNX, MOVE, RULE, PUSH, POP,
-	   SPECIAL, DEAD };
-    int op;
-    int x;
-    int y;
-    String s;
-    Setting(int op_in, int x_in = 0, int y_in = 0)
-	: op(op_in), x(x_in), y(y_in) { }
-    Setting(int op_in, const String &s_in) : op(op_in), s(s_in) { }
-    bool valid_op() const		{ return op >= FONT && op <= SPECIAL; }
-};
-
 class Metrics { public:
 
     typedef int Code;
@@ -33,22 +21,22 @@ class Metrics { public:
 
     void check() const;
 
-    Glyph boundary_glyph() const	{ return _boundary_glyph; }
-    Glyph emptyslot_glyph() const	{ return _emptyslot_glyph; }
+    Glyph boundary_glyph() const        { return _boundary_glyph; }
+    Glyph emptyslot_glyph() const       { return _emptyslot_glyph; }
 
-    String coding_scheme() const		{ return _coding_scheme; }
-    void set_coding_scheme(const String &s)	{ _coding_scheme = s; }
+    String coding_scheme() const                { return _coding_scheme; }
+    void set_coding_scheme(const String &s)     { _coding_scheme = s; }
 
-    int design_units() const			{ return _design_units; }
-    int units_per_em() const			{ return _units_per_em; }
-    void set_design_units(int du)		{ _design_units = du; }
+    int design_units() const                    { return _design_units; }
+    int units_per_em() const                    { return _units_per_em; }
+    void set_design_units(int du)               { _design_units = du; }
 
-    int n_mapped_fonts() const			{ return _mapped_fonts.size();}
+    int n_mapped_fonts() const                  { return _mapped_fonts.size();}
     const Efont::CharstringProgram *mapped_font(int i) const { return _mapped_fonts[i]; }
     const String &mapped_font_name(int i) const { return _mapped_font_names[i]; }
     int add_mapped_font(const Efont::CharstringProgram *, const String &);
 
-    inline int encoding_size() const		{ return _encoding.size(); }
+    inline int encoding_size() const            { return _encoding.size(); }
     inline bool valid_code(Code) const;
     inline bool nonvirtual_code(Code) const;
     PermString code_name(Code) const;
@@ -63,7 +51,7 @@ class Metrics { public:
     void encode_virtual(Code, PermString, uint32_t uni, const Vector<Setting> &, bool base_char);
 
     void add_altselector_code(Code, int altselector_type);
-    bool altselectors() const		{ return _altselectors.size() > 0; }
+    bool altselectors() const           { return _altselectors.size() > 0; }
 
     inline bool was_base_glyph(Code) const;
     inline Code base_code(Code) const;
@@ -101,57 +89,57 @@ class Metrics { public:
     void unparse() const;
 
     struct Ligature {
-	Code in2;
-	Code out;
-	Ligature(Code in2_, Code out_) : in2(in2_), out(out_) { }
+        Code in2;
+        Code out;
+        Ligature(Code in2_, Code out_) : in2(in2_), out(out_) { }
     };
 
     struct Kern {
-	Code in2;
-	int kern;
-	Kern(Code in2_, int kern_) : in2(in2_), kern(kern_) { }
+        Code in2;
+        int kern;
+        Kern(Code in2_, int kern_) : in2(in2_), kern(kern_) { }
     };
 
     struct VirtualChar {
-	PermString name;
-	Vector<Setting> setting;
+        PermString name;
+        Vector<Setting> setting;
     };
 
     struct Ligature3 {
-	Code in1;
-	Code in2;
-	Code out;
-	Ligature3(Code in1_, Code in2_, Code out_) : in1(in1_), in2(in2_), out(out_) { }
+        Code in1;
+        Code in2;
+        Code out;
+        Ligature3(Code in1_, Code in2_, Code out_) : in1(in1_), in2(in2_), out(out_) { }
         String unparse(const Metrics& m) const;
     };
 
   private:
 
     struct Char {
-	Glyph glyph;
-	Code base_code;
-	uint32_t unicode;
-	Vector<Ligature> ligatures;
-	Vector<Kern> kerns;
-	VirtualChar *virtual_char;
-	int pdx;
-	int pdy;
-	int adx;
-	Code built_in1;
-	Code built_in2;
-	int lookup_source;
-	enum { BUILT = 1, INTERMEDIATE = 2, CONTEXT_ONLY = 4, LIVE = 8,
-	       BASE_LIVE = 16, BASE_REP = 32, IS_FF = 64 };
-	int flags;
-
-	Char()				: virtual_char(0) { clear(); }
-	void clear();
-	void swap(Char &);
-	bool visible() const		{ return glyph != 0; }
-	bool visible_base() const	{ return glyph != 0 && glyph != VIRTUAL_GLYPH; }
-	bool flag(int f) const		{ return (flags & f) != 0; }
-	inline bool base_glyph() const;
-	bool context_setting(Code in1, Code in2) const;
+        Glyph glyph;
+        Code base_code;
+        uint32_t unicode;
+        Vector<Ligature> ligatures;
+        Vector<Kern> kerns;
+        VirtualChar *virtual_char;
+        int pdx;
+        int pdy;
+        int adx;
+        Code built_in1;
+        Code built_in2;
+        int lookup_source;
+        enum { BUILT = 1, INTERMEDIATE = 2, CONTEXT_ONLY = 4, LIVE = 8,
+               BASE_LIVE = 16, BASE_REP = 32, IS_FF = 64 };
+        int flags;
+
+        Char()                          : virtual_char(0) { clear(); }
+        void clear();
+        void swap(Char &);
+        bool visible() const            { return glyph != 0; }
+        bool visible_base() const       { return glyph != 0 && glyph != VIRTUAL_GLYPH; }
+        bool flag(int f) const          { return (flags & f) != 0; }
+        inline bool base_glyph() const;
+        bool context_setting(Code in1, Code in2) const;
     };
 
     Vector<Char> _encoding;
@@ -171,7 +159,7 @@ class Metrics { public:
     Vector<const Efont::CharstringProgram *> _mapped_fonts;
     Vector<String> _mapped_font_names;
 
-    Metrics(const Metrics &);	// does not exist
+    Metrics(const Metrics &);   // does not exist
     Metrics &operator=(const Metrics &); // does not exist
 
     inline void assign_emap(Glyph, Code);
@@ -191,17 +179,19 @@ class Metrics { public:
     class ChangedContext;
     void apply_ligature(const Vector<Code> &, const Substitution *, int lookup);
     void apply_single(Code cin, const Substitution *s, int lookup,
-		ChangedContext &ctx, const GlyphFilter &glyph_filter,
-		const Vector<PermString> &glyph_names);
+                ChangedContext &ctx, const GlyphFilter &glyph_filter,
+                const Vector<PermString> &glyph_names);
     void apply_simple_context_ligature(const Vector<Code> &codes,
-		const Substitution *s, int lookup, ChangedContext &ctx);
+                const Substitution *s, int lookup, ChangedContext &ctx,
+                const GlyphFilter &glyph_filter,
+                const Vector<PermString> &glyph_names);
     void apply_alternates_single(Code cin, const Substitution *s, int lookup,
-		const GlyphFilter &glyph_filter,
-		const Vector<PermString> &glyph_names);
+                const GlyphFilter &glyph_filter,
+                const Vector<PermString> &glyph_names);
     void apply_alternates_ligature(const Vector<Code> &codes,
-		const Substitution *s, int lookup,
-		const GlyphFilter &glyph_filter,
-		const Vector<PermString> &glyph_names);
+                const Substitution *s, int lookup,
+                const GlyphFilter &glyph_filter,
+                const Vector<PermString> &glyph_names);
 
     void unparse(const Char *) const;
 
@@ -224,36 +214,36 @@ inline Metrics::Glyph
 Metrics::glyph(Code code) const
 {
     if (code < 0 || code >= _encoding.size())
-	return 0;
+        return 0;
     else
-	return _encoding[code].glyph;
+        return _encoding[code].glyph;
 }
 
 inline uint32_t
 Metrics::unicode(Code code) const
 {
     if (code < 0 || code >= _encoding.size())
-	return 0;
+        return 0;
     else
-	return _encoding[code].unicode;
+        return _encoding[code].unicode;
 }
 
 inline Metrics::Glyph
 Metrics::base_glyph(Code code) const
 {
     if (code < 0 || code >= _encoding.size() || _encoding[code].base_code < 0)
-	return 0;
+        return 0;
     else
-	return _encoding[code].glyph;
+        return _encoding[code].glyph;
 }
 
 inline Metrics::Code
 Metrics::base_code(Code code) const
 {
     if (code < 0 || code >= _encoding.size())
-	return 0;
+        return 0;
     else
-	return _encoding[code].base_code;
+        return _encoding[code].base_code;
 }
 
 inline Metrics::Code
@@ -261,16 +251,16 @@ Metrics::encoding(Glyph g, Code after) c
 {
     Code c;
     if (g >= 0 && g < _emap.size() && (c = _emap.at_u(g)) >= -1)
-	return c < 0 || c >= after ? c : -1;
+        return c < 0 || c >= after ? c : -1;
     else
-	return hard_encoding(g, after);
+        return hard_encoding(g, after);
 }
 
 inline void
 Metrics::assign_emap(Glyph g, Code code)
 {
     if (g >= _emap.size())
-	_emap.resize(g + 1, -1);
+        _emap.resize(g + 1, -1);
     _emap[g] = (_emap[g] == -1 || _emap[g] == code ? code : -2);
 }
 
@@ -290,9 +280,9 @@ inline bool
 Metrics::was_base_glyph(Code code) const
 {
     if (code < 0 || code >= _encoding.size())
-	return 0;
+        return 0;
     else
-	return _encoding[code].base_glyph();
+        return _encoding[code].base_glyph();
 }
 
 #endif
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.1	2018-02-23 12:47:54.092971728 -0500
@@ -1,5 +1,5 @@
 '\"t
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
@@ -868,15 +868,19 @@ Do not generate a font map line for the
 .BI \-\-truetype\-directory= dir
 .TP 5
 .BI \-\-type42\-directory= dir
+.TP 5
+.BI \-\-directory= dir
 Set the directory used for various output types.  Each directory may be set
 by an environment variable, and defaults to a TDS directory in automatic
 mode, or to "." otherwise.  Environment variable names and default TDS
-locations are described in the Automatic Mode section above.
+locations are described in the Automatic Mode section above.  The
+.B \-\-directory
+option sets the default directory for all output types.
 '
 .Sp
 .TP 5
 .BI \-\-map\-file= filename
-Set file in which 
+Set file in which
 .B otftotfm
 will write a font map
 line for the font.  The default is the standard output in manual mode, and
@@ -956,7 +960,7 @@ have the following format:
 This tells
 .B otftotfm
 that the glyph named
-.I glyph 
+.I glyph
 translates into the first Unicode value in the
 .I choice
 list that has a character in the font.  \fIGlyph\fR and the
@@ -1042,7 +1046,7 @@ and
 .IR glyph2 .
 "{LK}" and "{KL}" inhibit both ligatures and kerns.
 .PP
-You can set the 
+You can set the
 .B \-\-boundary\-char
 and
 .B \-\-altselector\-char
@@ -1060,7 +1064,7 @@ has a default set of eight ligatures, na
     space l =: lslash ; space L =: Lslash ;
     question quoteleft =: questiondown ; exclam quoteleft =: exclamdown ;
     hyphen hyphen =: endash ; endash hyphen =: emdash ;
-    quoteleft quoteleft =: quotedblleft ; 
+    quoteleft quoteleft =: quotedblleft ;
     quoteright quoteright =: quotedblright
 .fi
 LIGKERN commands in the encoding file and
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.cc	2018-02-23 12:47:54.094971678 -0500
@@ -1,6 +1,6 @@
 /* otftotfm.cc -- driver for translating OpenType fonts to TeX metrics
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -63,91 +63,89 @@
 #ifdef HAVE_FCNTL_H
 # include <fcntl.h>
 #endif
-#ifdef _MSC_VER
-# include <io.h>
-#endif
 
 using namespace Efont;
 
-#define VERSION_OPT		301
-#define HELP_OPT		302
-#define QUERY_SCRIPTS_OPT	303
-#define QUERY_FEATURES_OPT	304
-#define KPATHSEA_DEBUG_OPT	305
-
-#define SCRIPT_OPT		311
-#define FEATURE_OPT		312
-#define ENCODING_OPT		313
-#define LITERAL_ENCODING_OPT	314
-#define EXTEND_OPT		315
-#define SLANT_OPT		316
-#define LETTERSPACE_OPT		317
-#define LIGKERN_OPT		318
-#define CODINGSCHEME_OPT	319
-#define UNICODING_OPT		320
-#define BOUNDARY_CHAR_OPT	321
-#define DESIGN_SIZE_OPT		322
-#define MINIMUM_KERN_OPT	323
-#define ALTSELECTOR_CHAR_OPT	324
-#define INCLUDE_ALTERNATES_OPT	325
-#define EXCLUDE_ALTERNATES_OPT	326
-#define CLEAR_ALTERNATES_OPT	327
-#define ALTSELECTOR_FEATURE_OPT	328
-#define DEFAULT_LIGKERN_OPT	329
-#define NO_ECOMMAND_OPT		330
-#define LETTER_FEATURE_OPT	331
-#define INCLUDE_SUBS_OPT	332
-#define EXCLUDE_SUBS_OPT	333
-#define CLEAR_SUBS_OPT		334
-#define SUBS_FILTER_OPT		335
-#define ALTERNATES_FILTER_OPT	336
-#define SPACE_FACTOR_OPT	337
-#define MATH_SPACING_OPT	338
-#define POSITION_OPT		339
-#define WARN_MISSING_OPT	340
-#define BASE_ENCODINGS_OPT	341
-#define FIXED_PITCH_OPT		342
-#define ITALIC_ANGLE_OPT	343
-#define PROPORTIONAL_WIDTH_OPT	344
-#define X_HEIGHT_OPT		345
-
-#define AUTOMATIC_OPT		350
-#define FONT_NAME_OPT		351
-#define QUIET_OPT		352
-#define GLYPHLIST_OPT		353
-#define VENDOR_OPT		354
-#define TYPEFACE_OPT		355
-#define NOCREATE_OPT		356
-#define VERBOSE_OPT		357
-#define FORCE_OPT		358
-
-#define VIRTUAL_OPT		360
-#define PL_OPT			361
-#define TFM_OPT			362
-#define MAP_FILE_OPT		363
-#define OUTPUT_ENCODING_OPT	364
-
-#define DIR_OPTS		380
-#define ENCODING_DIR_OPT	(DIR_OPTS + O_ENCODING)
-#define TFM_DIR_OPT		(DIR_OPTS + O_TFM)
-#define PL_DIR_OPT		(DIR_OPTS + O_PL)
-#define VF_DIR_OPT		(DIR_OPTS + O_VF)
-#define VPL_DIR_OPT		(DIR_OPTS + O_VPL)
-#define TYPE1_DIR_OPT		(DIR_OPTS + O_TYPE1)
-#define TYPE42_DIR_OPT		(DIR_OPTS + O_TYPE42)
-#define TRUETYPE_DIR_OPT	(DIR_OPTS + O_TRUETYPE)
-
-#define NO_OUTPUT_OPTS		400
-#define NO_ENCODING_OPT		(NO_OUTPUT_OPTS + G_ENCODING)
-#define NO_TYPE1_OPT		(NO_OUTPUT_OPTS + G_TYPE1)
-#define NO_DOTLESSJ_OPT		(NO_OUTPUT_OPTS + G_DOTLESSJ)
-#define NO_UPDMAP_OPT		(NO_OUTPUT_OPTS + G_UPDMAP)
-
-#define YES_OUTPUT_OPTS		2000
-#define TRUETYPE_OPT		(YES_OUTPUT_OPTS + G_TRUETYPE)
-#define TYPE42_OPT		(YES_OUTPUT_OPTS + G_TYPE42)
+#define VERSION_OPT             301
+#define HELP_OPT                302
+#define QUERY_SCRIPTS_OPT       303
+#define QUERY_FEATURES_OPT      304
+#define KPATHSEA_DEBUG_OPT      305
+
+#define SCRIPT_OPT              311
+#define FEATURE_OPT             312
+#define ENCODING_OPT            313
+#define LITERAL_ENCODING_OPT    314
+#define EXTEND_OPT              315
+#define SLANT_OPT               316
+#define LETTERSPACE_OPT         317
+#define LIGKERN_OPT             318
+#define CODINGSCHEME_OPT        319
+#define UNICODING_OPT           320
+#define BOUNDARY_CHAR_OPT       321
+#define DESIGN_SIZE_OPT         322
+#define MINIMUM_KERN_OPT        323
+#define ALTSELECTOR_CHAR_OPT    324
+#define INCLUDE_ALTERNATES_OPT  325
+#define EXCLUDE_ALTERNATES_OPT  326
+#define CLEAR_ALTERNATES_OPT    327
+#define ALTSELECTOR_FEATURE_OPT 328
+#define DEFAULT_LIGKERN_OPT     329
+#define NO_ECOMMAND_OPT         330
+#define LETTER_FEATURE_OPT      331
+#define INCLUDE_SUBS_OPT        332
+#define EXCLUDE_SUBS_OPT        333
+#define CLEAR_SUBS_OPT          334
+#define SUBS_FILTER_OPT         335
+#define ALTERNATES_FILTER_OPT   336
+#define SPACE_FACTOR_OPT        337
+#define MATH_SPACING_OPT        338
+#define POSITION_OPT            339
+#define WARN_MISSING_OPT        340
+#define BASE_ENCODINGS_OPT      341
+#define FIXED_PITCH_OPT         342
+#define ITALIC_ANGLE_OPT        343
+#define PROPORTIONAL_WIDTH_OPT  344
+#define X_HEIGHT_OPT            345
+
+#define AUTOMATIC_OPT           350
+#define FONT_NAME_OPT           351
+#define QUIET_OPT               352
+#define GLYPHLIST_OPT           353
+#define VENDOR_OPT              354
+#define TYPEFACE_OPT            355
+#define NOCREATE_OPT            356
+#define VERBOSE_OPT             357
+#define FORCE_OPT               358
+
+#define VIRTUAL_OPT             360
+#define PL_OPT                  361
+#define TFM_OPT                 362
+#define MAP_FILE_OPT            363
+#define OUTPUT_ENCODING_OPT     364
+
+#define DIR_OPTS                380
+#define ENCODING_DIR_OPT        (DIR_OPTS + O_ENCODING)
+#define TFM_DIR_OPT             (DIR_OPTS + O_TFM)
+#define PL_DIR_OPT              (DIR_OPTS + O_PL)
+#define VF_DIR_OPT              (DIR_OPTS + O_VF)
+#define VPL_DIR_OPT             (DIR_OPTS + O_VPL)
+#define TYPE1_DIR_OPT           (DIR_OPTS + O_TYPE1)
+#define TYPE42_DIR_OPT          (DIR_OPTS + O_TYPE42)
+#define TRUETYPE_DIR_OPT        (DIR_OPTS + O_TRUETYPE)
+#define DIR_OPT                 (DIR_OPTS + NUMODIR)
+
+#define NO_OUTPUT_OPTS          400
+#define NO_ENCODING_OPT         (NO_OUTPUT_OPTS + G_ENCODING)
+#define NO_TYPE1_OPT            (NO_OUTPUT_OPTS + G_TYPE1)
+#define NO_DOTLESSJ_OPT         (NO_OUTPUT_OPTS + G_DOTLESSJ)
+#define NO_UPDMAP_OPT           (NO_OUTPUT_OPTS + G_UPDMAP)
+
+#define YES_OUTPUT_OPTS         2000
+#define TRUETYPE_OPT            (YES_OUTPUT_OPTS + G_TRUETYPE)
+#define TYPE42_OPT              (YES_OUTPUT_OPTS + G_TYPE42)
 
-#define CHAR_OPTTYPE		(Clp_ValFirstUser)
+#define CHAR_OPTTYPE            (Clp_ValFirstUser)
 
 static Clp_Option options[] = {
 
@@ -194,7 +192,8 @@ static Clp_Option options[] = {
     { "italic-angle", 0, ITALIC_ANGLE_OPT, Clp_ValDouble, 0 },
     { "x-height", 0, X_HEIGHT_OPT, Clp_ValString, 0 },
 
-    { "pl", 'p', PL_OPT, 0, 0 },
+    { "pl", 'p', PL_OPT, 0, Clp_Negate },
+    { "tfm", 't', TFM_OPT, 0, Clp_Negate }, // not in documentation
     { "virtual", 0, VIRTUAL_OPT, 0, Clp_Negate },
     { "no-encoding", 0, NO_ENCODING_OPT, 0, 0 },
     { "no-type1", 0, NO_TYPE1_OPT, 0, 0 },
@@ -210,6 +209,7 @@ static Clp_Option options[] = {
     { "vendor", 'v', VENDOR_OPT, Clp_ValString, 0 },
     { "typeface", 0, TYPEFACE_OPT, Clp_ValString, 0 },
 
+    { "directory", 0, DIR_OPT, Clp_ValString, 0 },
     { "encoding-directory", 0, ENCODING_DIR_OPT, Clp_ValString, 0 },
     { "pl-directory", 0, PL_DIR_OPT, Clp_ValString, 0 },
     { "tfm-directory", 0, TFM_DIR_OPT, Clp_ValString, 0 },
@@ -229,7 +229,6 @@ static Clp_Option options[] = {
     { "help", 'h', HELP_OPT, 0, 0 },
     { "version", 0, VERSION_OPT, 0, 0 },
 
-    { "tfm", 't', TFM_OPT, 0, 0 }, // deprecated
     { "query-features", 0, QUERY_FEATURES_OPT, 0, 0 },
     { "qf", 0, QUERY_FEATURES_OPT, 0, 0 },
     { "query-scripts", 0, QUERY_SCRIPTS_OPT, 0, 0 },
@@ -286,7 +285,7 @@ static double x_height;
 static String out_encoding_file;
 static String out_encoding_name;
 
-int output_flags = G_ENCODING | G_METRICS | G_VMETRICS | G_PSFONTSMAP | G_TYPE1 | G_DOTLESSJ | G_UPDMAP | G_BINARY | G_TRUETYPE;
+unsigned output_flags = G_ENCODING | G_METRICS | G_VMETRICS | G_PSFONTSMAP | G_TYPE1 | G_DOTLESSJ | G_UPDMAP | G_TRUETYPE;
 
 bool automatic = false;
 bool verbose = false;
@@ -303,9 +302,9 @@ usage_error(ErrorHandler *errh, const ch
     va_list val;
     va_start(val, error_message);
     if (!error_message)
-	errh->message("Usage: %s [OPTION]... FONT", program_name);
+        errh->message("Usage: %s [OPTION]... FONT", program_name);
     else
-	errh->xmessage(ErrorHandler::e_error, error_message, val);
+        errh->xmessage(ErrorHandler::e_error, error_message, val);
     errh->message("Type %s --help for more information.", program_name);
     exit(1);
 }
@@ -323,7 +322,7 @@ encoding. Output files are written to th
 %<--automatic%> and the %<directory%> options).\n\
 \n\
 Usage: %s [-a] [OPTIONS] OTFFILE FONTNAME\n\n",
-	   program_name);
+           program_name);
     uerrh.message("\
 Font feature and transformation options:\n\
   -s, --script=SCRIPT[.LANG]   Use features for script SCRIPT[.LANG] [latn].\n\
@@ -391,6 +390,7 @@ File location options:\n\
       --encoding-directory=DIR Put encoding files in DIR [.|automatic].\n\
       --type1-directory=DIR    Put Type 1 fonts in DIR [automatic].\n\
       --truetype-directory=DIR Put TrueType fonts in DIR [automatic].\n\
+      --directory=DIR          Put output in DIR [.|automatic].\n\
       --map-file=FILE          Update FILE with psfonts.map information [-].\n\
 \n\
 Other options:\n\
@@ -449,14 +449,14 @@ suffix_font_name(const String &font_name
 {
     const char *begin = font_name.begin(), *end = font_name.end();
     while (end > begin && isdigit((unsigned char) end[-1]))
-	--end;
+        --end;
     if (end < font_name.end() && end > begin && end[-1] != '-' && end[-1] != '+')
-	end = font_name.end();
+        end = font_name.end();
     else
-	while (end > begin && (end[-1] == '-' || end[-1] == '+'))
-	    --end;
+        while (end > begin && (end[-1] == '-' || end[-1] == '+'))
+            --end;
     if (end == begin)
-	end = font_name.end();
+        end = font_name.end();
     return font_name.substring(begin, end) + suffix + font_name.substring(end, font_name.end());
 }
 
@@ -470,40 +470,40 @@ static double
 get_design_size(const FontInfo &finfo)
 {
     try {
-	String gpos_table = finfo.otf->table("GPOS");
-	if (!gpos_table)
-	    throw OpenType::Error();
-
-	ErrorHandler *errh = ErrorHandler::silent_handler();
-	OpenType::Gpos gpos(gpos_table, errh);
-
-	// extract 'size' feature(s)
-	int required_fid;
-	Vector<int> fids;
-	for (const OpenType::Tag *t = interesting_scripts.begin(); t < interesting_scripts.end(); t += 2)
-	    gpos.script_list().features(t[0], t[1], required_fid, fids, 0, false);
-
-	int size_fid = gpos.feature_list().find(OpenType::Tag("size"), fids);
-	if (size_fid < 0)
-	    throw OpenType::Error();
-
-	// old Adobe fonts implement an old, incorrect idea
-	// of what the FeatureParams offset means.
-	OpenType::Name name(finfo.otf->table("name"), errh);
-	OpenType::Data size_data = gpos.feature_list().size_params(size_fid, name, errh);
-	if (!size_data.length())
-	    throw OpenType::Error();
-
-	double result = size_data.u16(0) / 10.;
-	// check for insane design sizes
-	if (result < 1 || result > 1000)
-	    throw OpenType::Error();
+        String gpos_table = finfo.otf->table("GPOS");
+        if (!gpos_table)
+            throw OpenType::Error();
+
+        ErrorHandler *errh = ErrorHandler::silent_handler();
+        OpenType::Gpos gpos(gpos_table, errh);
+
+        // extract 'size' feature(s)
+        int required_fid;
+        Vector<int> fids;
+        for (const OpenType::Tag *t = interesting_scripts.begin(); t < interesting_scripts.end(); t += 2)
+            gpos.script_list().features(t[0], t[1], required_fid, fids, 0, false);
+
+        int size_fid = gpos.feature_list().find(OpenType::Tag("size"), fids);
+        if (size_fid < 0)
+            throw OpenType::Error();
+
+        // old Adobe fonts implement an old, incorrect idea
+        // of what the FeatureParams offset means.
+        OpenType::Name name(finfo.otf->table("name"), errh);
+        OpenType::Data size_data = gpos.feature_list().size_params(size_fid, name, errh);
+        if (!size_data.length())
+            throw OpenType::Error();
+
+        double result = size_data.u16(0) / 10.;
+        // check for insane design sizes
+        if (result < 1 || result > 1000)
+            throw OpenType::Error();
 
-	// return a number in 'pt', not 'bp'
-	return result * 72.27 / 72.;
+        // return a number in 'pt', not 'bp'
+        return result * 72.27 / 72.;
 
     } catch (OpenType::Error) {
-	return 10.0;
+        return 10.0;
     }
 }
 
@@ -556,9 +556,9 @@ void Printer::print(const char* prefix,
 String Printer::render(double value) const {
     value = transform(value);
     if (round_ || value == 0 || (value > 0.01 && value - floor(value) < 0.01))
-	return String(value);
+        return String(value);
     else {
-	char buf[128];
+        char buf[128];
         sprintf(buf, "%.4f", value);
         return String(buf);
     }
@@ -574,21 +574,21 @@ font_slant(const FontInfo &finfo)
 
 static void
 output_pl(Metrics &metrics, const String &ps_name, int boundary_char,
-	  const FontInfo &finfo, bool vpl,
-	  const String &filename, ErrorHandler *errh)
+          const FontInfo &finfo, bool vpl,
+          const String &filename, ErrorHandler *errh)
 {
     // create file
     if (no_create) {
-	errh->message("would create %s", filename.c_str());
-	return;
+        errh->message("would create %s", filename.c_str());
+        return;
     }
 
     if (verbose)
-	errh->message("creating %s", filename.c_str());
-    FILE *f = fopen(filename.c_str(), "wb");
+        errh->message("creating %s", filename.c_str());
+    FILE *f = fopen(filename.c_str(), "w");
     if (!f) {
-	errh->error("%s: %s", filename.c_str(), strerror(errno));
-	return;
+        errh->error("%s: %s", filename.c_str(), strerror(errno));
+        return;
     }
 
     // XXX check DESIGNSIZE and DESIGNUNITS for correctness
@@ -598,139 +598,139 @@ output_pl(Metrics &metrics, const String
     // calculate a TeX FAMILY name using afm2tfm's algorithm
     String family_name = String("TeX-") + ps_name;
     if (family_name.length() > 19)
-	family_name = family_name.substring(0, 9) + family_name.substring(-10);
+        family_name = family_name.substring(0, 9) + family_name.substring(-10);
     fprintf(f, "(FAMILY %s)\n", family_name.c_str());
 
     if (metrics.coding_scheme())
-	fprintf(f, "(CODINGSCHEME %.39s)\n", String(metrics.coding_scheme()).c_str());
+        fprintf(f, "(CODINGSCHEME %.39s)\n", String(metrics.coding_scheme()).c_str());
     int design_units = metrics.design_units();
 
     if (design_size <= 0)
-	design_size = get_design_size(finfo);
+        design_size = get_design_size(finfo);
     max_printed_real = 0;
 
     fprintf(f, "(DESIGNSIZE R %.1f)\n"
-	    "(DESIGNUNITS R %d.0)\n"
-	    "(COMMENT DESIGNSIZE (1 em) IS IN POINTS)\n"
-	    "(COMMENT OTHER DIMENSIONS ARE MULTIPLES OF DESIGNSIZE/%d)\n"
-	    "(FONTDIMEN\n", design_size, design_units, design_units);
+            "(DESIGNUNITS R %d.0)\n"
+            "(COMMENT DESIGNSIZE (1 em) IS IN POINTS)\n"
+            "(COMMENT OTHER DIMENSIONS ARE MULTIPLES OF DESIGNSIZE/%d)\n"
+            "(FONTDIMEN\n", design_size, design_units, design_units);
 
     // figure out font dimensions
     Transform font_xform;
     if (extend)
-	font_xform.scale(extend, 1);
+        font_xform.scale(extend, 1);
     if (slant)
-	font_xform.shear(slant);
+        font_xform.shear(slant);
     double bounds[4], width;
     Printer pr(f, design_units, metrics.units_per_em());
 
     double actual_slant = font_slant(finfo);
     if (actual_slant)
-	fprintf(f, "   (SLANT R %g)\n", actual_slant);
+        fprintf(f, "   (SLANT R %g)\n", actual_slant);
 
     if (char_bounds(bounds, width, finfo, font_xform, ' ')) {
-	// advance space width by letterspacing, scale by space_factor
-	double space_width = (width + (vpl ? letterspace : 0)) * space_factor;
-	pr.print("   (SPACE", space_width);
-	if (finfo.is_fixed_pitch()) {
-	    // fixed-pitch: no space stretch or shrink
-	    pr.print("   (STRETCH", 0);
-	    pr.print("   (SHRINK", 0);
-	    pr.print("   (EXTRASPACE", space_width);
-	} else {
-	    pr.print("   (STRETCH", space_width / 2.);
-	    pr.print("   (SHRINK", space_width / 3.);
-	    pr.print("   (EXTRASPACE", space_width / 6.);
-	}
+        // advance space width by letterspacing, scale by space_factor
+        double space_width = (width + (vpl ? letterspace : 0)) * space_factor;
+        pr.print("   (SPACE", space_width);
+        if (finfo.is_fixed_pitch()) {
+            // fixed-pitch: no space stretch or shrink
+            pr.print("   (STRETCH", 0);
+            pr.print("   (SHRINK", 0);
+            pr.print("   (EXTRASPACE", space_width);
+        } else {
+            pr.print("   (STRETCH", space_width / 2.);
+            pr.print("   (SHRINK", space_width / 3.);
+            pr.print("   (EXTRASPACE", space_width / 6.);
+        }
     }
 
     double x_height = finfo.x_height(font_xform);
     if (x_height < finfo.units_per_em())
-	pr.print("   (XHEIGHT", x_height);
+        pr.print("   (XHEIGHT", x_height);
 
     pr.print("   (QUAD", finfo.units_per_em());
     fprintf(f, "   )\n");
 
     if (boundary_char >= 0)
-	fprintf(f, "(BOUNDARYCHAR D %d)\n", boundary_char);
+        fprintf(f, "(BOUNDARYCHAR D %d)\n", boundary_char);
 
     // figure out font mapping
     int mapped_font0 = 0;
     Vector<int> font_mapping;
     if (vpl) {
-	int vpl_first_font = (metrics.need_base() ? 0 : 1);
-	font_mapping.assign(metrics.n_mapped_fonts(), 0);
-	if (vpl_first_font == 1 && font_mapping.size() == 1)
-	    font_mapping.push_back(0);
-	// how many times is each font used?
-	Vector<Setting> settings;
-	for (int i = 0; i < 256; i++)
-	    if (metrics.setting(i, settings)) {
-		int font_number = 0;
-		for (const Setting *s = settings.begin(); s < settings.end(); s++)
-		    if (s->op == Setting::SHOW)
-			font_mapping[font_number]++;
-		    else if (s->op == Setting::FONT)
-			font_number = (int) s->x;
-	    }
-	// make sure the most-used font is number 0
-	mapped_font0 = std::max_element(font_mapping.begin(), font_mapping.end()) - font_mapping.begin();
-	// prepare the mapping
-	for (int i = vpl_first_font; i < font_mapping.size(); i++)
-	    font_mapping[i] = i - vpl_first_font;
-	font_mapping[mapped_font0] = 0;
-	font_mapping[vpl_first_font] = mapped_font0 - vpl_first_font;
-	if (vpl_first_font != 0)
-	    font_mapping[0] = font_mapping.size() - 1;
-	// write MAPFONT
-	for (int i = 0; i < metrics.n_mapped_fonts() - vpl_first_font; i++) {
-	    int j = std::find(font_mapping.begin(), font_mapping.end(), i) - font_mapping.begin();
-	    String name = metrics.mapped_font_name(j);
-	    if (!name)
-		name = make_base_font_name(font_name);
-	    fprintf(f, "(MAPFONT D %d\n   (FONTNAME %s)\n   (FONTDSIZE R %.1f)\n   )\n", i, name.c_str(), design_size);
-	}
+        int vpl_first_font = (metrics.need_base() ? 0 : 1);
+        font_mapping.assign(metrics.n_mapped_fonts(), 0);
+        if (vpl_first_font == 1 && font_mapping.size() == 1)
+            font_mapping.push_back(0);
+        // how many times is each font used?
+        Vector<Setting> settings;
+        for (int i = 0; i < 256; i++)
+            if (metrics.setting(i, settings)) {
+                int font_number = 0;
+                for (const Setting *s = settings.begin(); s < settings.end(); s++)
+                    if (s->op == Setting::SHOW)
+                        font_mapping[font_number]++;
+                    else if (s->op == Setting::FONT)
+                        font_number = (int) s->x;
+            }
+        // make sure the most-used font is number 0
+        mapped_font0 = std::max_element(font_mapping.begin(), font_mapping.end()) - font_mapping.begin();
+        // prepare the mapping
+        for (int i = vpl_first_font; i < font_mapping.size(); i++)
+            font_mapping[i] = i - vpl_first_font;
+        font_mapping[mapped_font0] = 0;
+        font_mapping[vpl_first_font] = mapped_font0 - vpl_first_font;
+        if (vpl_first_font != 0)
+            font_mapping[0] = font_mapping.size() - 1;
+        // write MAPFONT
+        for (int i = 0; i < metrics.n_mapped_fonts() - vpl_first_font; i++) {
+            int j = std::find(font_mapping.begin(), font_mapping.end(), i) - font_mapping.begin();
+            String name = metrics.mapped_font_name(j);
+            if (!name)
+                name = make_base_font_name(font_name);
+            fprintf(f, "(MAPFONT D %d\n   (FONTNAME %s)\n   (FONTDSIZE R %.1f)\n   )\n", i, name.c_str(), design_size);
+        }
     } else
-	for (int i = 0; i < metrics.n_mapped_fonts(); i++)
-	    font_mapping.push_back(i);
+        for (int i = 0; i < metrics.n_mapped_fonts(); i++)
+            font_mapping.push_back(i);
 
     // figure out the proper names and numbers for glyphs
     Vector<String> glyph_ids;
     Vector<String> glyph_comments(257, String());
     Vector<String> glyph_base_comments(257, String());
     for (int i = 0; i < metrics.encoding_size(); i++) {
-	if (metrics.glyph(i)) {
-	    PermString name = metrics.code_name(i), expected_name;
-	    if (i >= '0' && i <= '9')
-		expected_name = digit_names[i - '0'];
-	    else if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z'))
-		expected_name = PermString((char)i);
-	    String glyph_comment;
-	    if (name != expected_name)
-		glyph_comment = " (COMMENT " + String(name) + ")";
-
-	    int base = metrics.base_code(i);
-	    if (base >= 0 && base < 256)
-		glyph_base_comments[base] = glyph_comment;
+        if (metrics.glyph(i)) {
+            PermString name = metrics.code_name(i), expected_name;
+            if (i >= '0' && i <= '9')
+                expected_name = digit_names[i - '0'];
+            else if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z'))
+                expected_name = PermString((char)i);
+            String glyph_comment;
+            if (name != expected_name)
+                glyph_comment = " (COMMENT " + String(name) + ")";
+
+            int base = metrics.base_code(i);
+            if (base >= 0 && base < 256)
+                glyph_base_comments[base] = glyph_comment;
 
-	    if (i >= 256)
-		continue;
+            if (i >= 256)
+                continue;
 
             char* expected_name_end;
-	    if (expected_name
+            if (expected_name
                 && (name == expected_name
                     || (name.length() == 7
                         && memcmp(name.data(), "uni00", 5) == 0
                         && strtol(name.c_str() + 3, &expected_name_end, 16) == i
                         && *expected_name_end == 0)))
-		glyph_ids.push_back("C " + String((char)i));
-	    else
-		glyph_ids.push_back("D " + String(i));
+                glyph_ids.push_back("C " + String((char)i));
+            else
+                glyph_ids.push_back("D " + String(i));
 
-	    glyph_comments[i] = glyph_base_comments[i] = glyph_comment;
+            glyph_comments[i] = glyph_base_comments[i] = glyph_comment;
 
-	} else if (i < 256)
-	    glyph_ids.push_back("D " + String(i));
+        } else if (i < 256)
+            glyph_ids.push_back("D " + String(i));
     }
     // finally, BOUNDARYCHAR
     glyph_ids.push_back("BOUNDARYCHAR");
@@ -741,38 +741,50 @@ output_pl(Metrics &metrics, const String
     // don't print KRN x after printing LIG x
     uint32_t used[8];
     bool any_ligs = false;
+    StringAccum omitted_clig_sa;
     for (int i = 0; i <= 256; i++)
-	if (metrics.glyph(i) && minimum_kern < 10000) {
-	    int any_lig = metrics.ligatures(i, lig_code2, lig_outcode, lig_context);
-	    int any_kern = metrics.kerns(i, kern_code2, kern_amt);
-	    if (any_lig || any_kern) {
-		StringAccum kern_sa;
-		memset(&used[0], 0, 32);
-		for (int j = 0; j < lig_code2.size(); j++) {
-		    kern_sa << "   (" << lig_context_str(lig_context[j])
-			    << ' ' << glyph_ids[lig_code2[j]]
-			    << ' ' << glyph_ids[lig_outcode[j]]
-			    << ')' << glyph_comments[lig_code2[j]]
-			    << glyph_comments[lig_outcode[j]] << '\n';
-		    used[lig_code2[j] >> 5] |= (1 << (lig_code2[j] & 0x1F));
-		}
-		for (Vector<int>::const_iterator k2 = kern_code2.begin(); k2 < kern_code2.end(); k2++)
-		    if (!(used[*k2 >> 5] & (1 << (*k2 & 0x1F)))) {
-			double this_kern = kern_amt[k2 - kern_code2.begin()];
-			if (fabs(this_kern) >= minimum_kern)
-			    kern_sa << "   (KRN " << glyph_ids[*k2]
-				    << " R " << pr.render(this_kern)
-				    << ')' << glyph_comments[*k2] << '\n';
-		    }
-		if (kern_sa) {
-		    if (any_ligs)
-			fprintf(f, "\n");
-		    fprintf(f, "   (LABEL %s)%s\n%s   (STOP)\n", glyph_ids[i].c_str(), glyph_comments[i].c_str(), kern_sa.c_str());
-		    any_ligs = true;
-		}
-	    }
-	}
+        if (metrics.glyph(i) && minimum_kern < 10000) {
+            int any_lig = metrics.ligatures(i, lig_code2, lig_outcode, lig_context);
+            int any_kern = metrics.kerns(i, kern_code2, kern_amt);
+            if (any_lig || any_kern) {
+                StringAccum kern_sa;
+                memset(used, 0, sizeof(used));
+                for (int j = 0; j < lig_code2.size(); j++) {
+                    if (lig_outcode[j] < 257) {
+                        kern_sa << "   (" << lig_context_str(lig_context[j])
+                                << ' ' << glyph_ids[lig_code2[j]]
+                                << ' ' << glyph_ids[lig_outcode[j]]
+                                << ')' << glyph_comments[lig_code2[j]]
+                                << glyph_comments[lig_outcode[j]] << '\n';
+                        used[lig_code2[j] >> 5] |= (1 << (lig_code2[j] & 0x1F));
+                    } else {
+                        omitted_clig_sa << "(COMMENT omitted "
+                                << lig_context_str(lig_context[j])
+                                << ' ' << metrics.code_name(i)
+                                << ' ' << metrics.code_name(lig_code2[j])
+                                << ' ' << metrics.code_name(lig_outcode[j])
+                                << ")\n";
+                    }
+                }
+                for (Vector<int>::const_iterator k2 = kern_code2.begin(); k2 < kern_code2.end(); k2++)
+                    if (!(used[*k2 >> 5] & (1 << (*k2 & 0x1F)))) {
+                        double this_kern = kern_amt[k2 - kern_code2.begin()];
+                        if (fabs(this_kern) >= minimum_kern)
+                            kern_sa << "   (KRN " << glyph_ids[*k2]
+                                    << " R " << pr.render(this_kern)
+                                    << ')' << glyph_comments[*k2] << '\n';
+                    }
+                if (kern_sa) {
+                    if (any_ligs)
+                        fprintf(f, "\n");
+                    fprintf(f, "   (LABEL %s)%s\n%s   (STOP)\n", glyph_ids[i].c_str(), glyph_comments[i].c_str(), kern_sa.c_str());
+                    any_ligs = true;
+                }
+            }
+        }
     fprintf(f, "   )\n");
+    if (omitted_clig_sa)
+        fprintf(f, "%s\n", omitted_clig_sa.c_str());
 
     // CHARACTERs
     Vector<Setting> settings;
@@ -780,121 +792,121 @@ output_pl(Metrics &metrics, const String
     Vector<Point> push_stack;
 
     for (int i = 0; i < 256; i++)
-	if (metrics.setting(i, settings)) {
-	    fprintf(f, "(CHARACTER %s%s\n", glyph_ids[i].c_str(), glyph_comments[i].c_str());
+        if (metrics.setting(i, settings)) {
+            fprintf(f, "(CHARACTER %s%s\n", glyph_ids[i].c_str(), glyph_comments[i].c_str());
 
-	    // unparse settings into DVI commands
-	    sa.clear();
-	    push_stack.clear();
-	    CharstringBounds boundser(font_xform);
-	    int program_number = mapped_font0;
-	    const CharstringProgram *program = finfo.program();
-	    for (const Setting *s = settings.begin(); s < settings.end(); s++)
-		switch (s->op) {
-
-		  case Setting::SHOW:
-		    if (vpl || program == finfo.program())
-			boundser.char_bounds(program->glyph_context(s->y));
-		    // 3.Aug.2004 -- reported by Marco Kuhlmann: Don't use
-		    // glyph_ids[] array when looking at a different font.
-		    if (program_number == 0)
-			sa << "      (SETCHAR " << glyph_ids[s->x] << ')' << glyph_base_comments[s->x] << "\n";
-		    else
-			sa << "      (SETCHAR D " << s->x << ")\n";
-		    break;
-
-		  case Setting::MOVE: {
-		      int x = 0, y = 0;
-		      while (s+1 < settings.end() && s[1].op == Setting::MOVE)
-			  x += s->x, y += s->y, s++;
-		      if (vpl)
-			  boundser.translate(s->x + x, s->y + y);
-		      if (s->x + x)
-			  sa << "      (MOVERIGHT R " << pr.render(s->x + x) << ")\n";
-		      if (s->y + y)
-			  sa << "      (MOVEUP R " << pr.render(s->y + y) << ")\n";
-		      break;
-		  }
-
-		  case Setting::RULE:
-		    if (vpl) {
-			boundser.mark(Point(0, 0));
-			boundser.mark(Point(s->x, s->y));
-			boundser.translate(s->x, 0);
-		    }
-		    sa << "      (SETRULE R " << pr.render(s->y) << " R " << pr.render(s->x) << ")\n";
-		    break;
-
-		  case Setting::FONT:
-		    if ((int) s->x != program_number) {
-			program = metrics.mapped_font((int) s->x);
-			program_number = (int) s->x;
-			sa << "      (SELECTFONT D " << font_mapping[program_number] << ")\n";
-		    }
-		    break;
-
-		  case Setting::PUSH:
-		    push_stack.push_back(boundser.transform(Point(0, 0)));
-		    sa << "      (PUSH)\n";
-		    break;
-
-		  case Setting::POP: {
-		      assert(push_stack.size());
-		      Point p = push_stack.back() - boundser.transform(Point(0, 0));
-		      if (vpl)
-			  boundser.translate(p.x, p.y);
-		      push_stack.pop_back();
-		      sa << "      (POP)\n";
-		      break;
-		  }
-
-		  case Setting::SPECIAL: {
-		      bool needhex = false;
-		      for (const char *str = s->s.begin(); str < s->s.end() && !needhex; str++)
-			  if (*str < ' ' || *str > '~' || *str == '(' || *str == ')')
-			      needhex = true;
-		      if (needhex) {
-			  sa << "      (SPECIALHEX ";
-			  for (const char *str = s->s.begin(); str < s->s.end(); str++) {
-			      static const char hexdig[] = "0123456789ABCDEF";
-			      int val = (unsigned char) *str;
-			      sa << hexdig[val >> 4] << hexdig[val & 0xF];
-			  }
-			  sa << ")\n";
-		      } else
-			  sa << "      (SPECIAL " << s->s << ")\n";
-		      break;
-		  }
-
-		}
-
-	    assert(push_stack.size() == 0);
-
-	    // output information
-	    boundser.output(bounds, width);
-	    pr.print("   (CHARWD", width);
-	    if (bounds[3] > 0)
-		pr.print("   (CHARHT", bounds[3]);
-	    if (bounds[1] < 0)
-		pr.print("   (CHARDP", -bounds[1]);
-	    if (bounds[2] > width)
-		pr.print_transformed("   (CHARIC", pr.transform(bounds[2]) - pr.transform(width));
-	    if (vpl && (settings.size() > 1 || settings[0].op != Setting::SHOW))
-		fprintf(f, "   (MAP\n%s      )\n", sa.c_str());
-	    fprintf(f, "   )\n");
-	}
+            // unparse settings into DVI commands
+            sa.clear();
+            push_stack.clear();
+            CharstringBounds boundser(font_xform);
+            int program_number = mapped_font0;
+            const CharstringProgram *program = finfo.program();
+            for (const Setting *s = settings.begin(); s < settings.end(); s++)
+                switch (s->op) {
+
+                  case Setting::SHOW:
+                    if (vpl || program == finfo.program())
+                        boundser.char_bounds(program->glyph_context(s->y));
+                    // 3.Aug.2004 -- reported by Marco Kuhlmann: Don't use
+                    // glyph_ids[] array when looking at a different font.
+                    if (program_number == 0)
+                        sa << "      (SETCHAR " << glyph_ids[s->x] << ')' << glyph_base_comments[s->x] << "\n";
+                    else
+                        sa << "      (SETCHAR D " << s->x << ")\n";
+                    break;
+
+                  case Setting::MOVE: {
+                      int x = 0, y = 0;
+                      while (s+1 < settings.end() && s[1].op == Setting::MOVE)
+                          x += s->x, y += s->y, s++;
+                      if (vpl)
+                          boundser.translate(s->x + x, s->y + y);
+                      if (s->x + x)
+                          sa << "      (MOVERIGHT R " << pr.render(s->x + x) << ")\n";
+                      if (s->y + y)
+                          sa << "      (MOVEUP R " << pr.render(s->y + y) << ")\n";
+                      break;
+                  }
+
+                  case Setting::RULE:
+                    if (vpl) {
+                        boundser.mark(Point(0, 0));
+                        boundser.mark(Point(s->x, s->y));
+                        boundser.translate(s->x, 0);
+                    }
+                    sa << "      (SETRULE R " << pr.render(s->y) << " R " << pr.render(s->x) << ")\n";
+                    break;
+
+                  case Setting::FONT:
+                    if ((int) s->x != program_number) {
+                        program = metrics.mapped_font((int) s->x);
+                        program_number = (int) s->x;
+                        sa << "      (SELECTFONT D " << font_mapping[program_number] << ")\n";
+                    }
+                    break;
+
+                  case Setting::PUSH:
+                    push_stack.push_back(boundser.transform(Point(0, 0)));
+                    sa << "      (PUSH)\n";
+                    break;
+
+                  case Setting::POP: {
+                      assert(push_stack.size());
+                      Point p = push_stack.back() - boundser.transform(Point(0, 0));
+                      if (vpl)
+                          boundser.translate(p.x, p.y);
+                      push_stack.pop_back();
+                      sa << "      (POP)\n";
+                      break;
+                  }
+
+                  case Setting::SPECIAL: {
+                      bool needhex = false;
+                      for (const char *str = s->s.begin(); str < s->s.end() && !needhex; str++)
+                          if (*str < ' ' || *str > '~' || *str == '(' || *str == ')')
+                              needhex = true;
+                      if (needhex) {
+                          sa << "      (SPECIALHEX ";
+                          for (const char *str = s->s.begin(); str < s->s.end(); str++) {
+                              static const char hexdig[] = "0123456789ABCDEF";
+                              int val = (unsigned char) *str;
+                              sa << hexdig[val >> 4] << hexdig[val & 0xF];
+                          }
+                          sa << ")\n";
+                      } else
+                          sa << "      (SPECIAL " << s->s << ")\n";
+                      break;
+                  }
+
+                }
+
+            assert(push_stack.size() == 0);
+
+            // output information
+            boundser.output(bounds, width);
+            pr.print("   (CHARWD", width);
+            if (bounds[3] > 0)
+                pr.print("   (CHARHT", bounds[3]);
+            if (bounds[1] < 0)
+                pr.print("   (CHARDP", -bounds[1]);
+            if (bounds[2] > width)
+                pr.print_transformed("   (CHARIC", pr.transform(bounds[2]) - pr.transform(width));
+            if (vpl && (settings.size() > 1 || settings[0].op != Setting::SHOW))
+                fprintf(f, "   (MAP\n%s      )\n", sa.c_str());
+            fprintf(f, "   )\n");
+        }
 
     // at last, close the file
     fclose(f);
 
     // Did we print a number too big for TeX to handle?  If so, try again.
     if (max_printed_real >= 2047) {
-	if (metrics.design_units() <= 1)
-	    errh->fatal("This font appears to be broken.  It has characters so big that the PL format\ncannot represent them.");
-	metrics.set_design_units(metrics.design_units() > 200 ? metrics.design_units() - 250 : 1);
-	if (verbose)
-	    errh->message("the font%,s metrics overflow the limits of PL files\n(reducing DESIGNUNITS to %d and trying again)", metrics.design_units());
-	output_pl(metrics, ps_name, boundary_char, finfo, vpl, filename, errh);
+        if (metrics.design_units() <= 1)
+            errh->fatal("This font appears to be broken.  It has characters so big that the PL format\ncannot represent them.");
+        metrics.set_design_units(metrics.design_units() > 200 ? metrics.design_units() - 250 : 1);
+        if (verbose)
+            errh->message("the font%,s metrics overflow the limits of PL files\n(reducing DESIGNUNITS to %d and trying again)", metrics.design_units());
+        output_pl(metrics, ps_name, boundary_char, finfo, vpl, filename, errh);
     }
 }
 
@@ -903,7 +915,7 @@ struct Lookup {
     bool required;
     Vector<OpenType::Tag> features;
     GlyphFilter* filter;
-    Lookup()			: used(false), required(false), filter(0) { }
+    Lookup()                    : used(false), required(false), filter(0) { }
 };
 
 static void
@@ -914,81 +926,81 @@ find_lookups(const OpenType::ScriptList&
 
     // go over all scripts
     for (int i = 0; i < interesting_scripts.size(); i += 2) {
-	OpenType::Tag script = interesting_scripts[i];
-	OpenType::Tag langsys = interesting_scripts[i+1];
+        OpenType::Tag script = interesting_scripts[i];
+        OpenType::Tag langsys = interesting_scripts[i+1];
 
-	// collect features applying to this script
-	scripts.features(script, langsys, required, fids, errh);
+        // collect features applying to this script
+        scripts.features(script, langsys, required, fids, errh);
 
-	// only use the selected features
-	features.filter(fids, interesting_features);
+        // only use the selected features
+        features.filter(fids, interesting_features);
 
-	// mark features as having been used
-	for (int j = (required < 0 ? 0 : -1); j < fids.size(); j++) {
-	    int fid = (j < 0 ? required : fids[j]);
-	    OpenType::Tag ftag = features.tag(fid);
-	    if (features.lookups(fid, lookupids, errh) < 0)
-		lookupids.clear();
-	    for (int k = 0; k < lookupids.size(); k++) {
-		int l = lookupids[k];
-		if (l < 0 || l >= lookups.size())
-		    errh->error("lookup for %<%s%> feature out of range", OpenType::Tag::langsys_text(script, langsys).c_str());
-		else {
-		    lookups[l].used = true;
-		    lookups[l].features.push_back(ftag);
-		    if (j < 0)
-			lookups[l].required = true;
-		}
-	    }
-	}
+        // mark features as having been used
+        for (int j = (required < 0 ? 0 : -1); j < fids.size(); j++) {
+            int fid = (j < 0 ? required : fids[j]);
+            OpenType::Tag ftag = features.tag(fid);
+            if (features.lookups(fid, lookupids, errh) < 0)
+                lookupids.clear();
+            for (int k = 0; k < lookupids.size(); k++) {
+                int l = lookupids[k];
+                if (l < 0 || l >= lookups.size())
+                    errh->error("lookup for %<%s%> feature out of range", OpenType::Tag::langsys_text(script, langsys).c_str());
+                else {
+                    lookups[l].used = true;
+                    lookups[l].features.push_back(ftag);
+                    if (j < 0)
+                        lookups[l].required = true;
+                }
+            }
+        }
     }
 
     // now check for compatible glyph filters
     for (Lookup* l = lookups.begin(); l < lookups.end(); l++)
-	if (l->used && !l->required) {
-	    l->filter = feature_filters[l->features[0]];
-	    for (OpenType::Tag* ft = l->features.begin() + 1; ft < l->features.end(); ft++)
-		if (!l->filter->check_eq(*feature_filters[*ft])) {
-		    errh->error("%<%s%> and %<%s%> features share a lookup, but have different filters", l->features[0].text().c_str(), ft->text().c_str());
-		    break;
-		}
-	}
+        if (l->used && !l->required) {
+            l->filter = feature_filters[l->features[0]];
+            for (OpenType::Tag* ft = l->features.begin() + 1; ft < l->features.end(); ft++)
+                if (!l->filter->check_eq(*feature_filters[*ft])) {
+                    errh->error("%<%s%> and %<%s%> features share a lookup, but have different filters", l->features[0].text().c_str(), ft->text().c_str());
+                    break;
+                }
+        }
 }
 
 static int
 write_encoding_file(String &filename, const String &encoding_name,
-		    StringAccum &contents, ErrorHandler *errh)
+                    StringAccum &contents, ErrorHandler *errh)
 {
     FILE *f;
     int ok_retval = (access(filename.c_str(), R_OK) >= 0 ? 0 : 1);
 
     if (no_create) {
-	errh->message((ok_retval ? "would create encoding file %s" : "would update encoding file %s"), filename.c_str());
-	return ok_retval;
+        errh->message((ok_retval ? "would create encoding file %s" : "would update encoding file %s"), filename.c_str());
+        return ok_retval;
     } else if (verbose)
-	errh->message((ok_retval ? "creating encoding file %s" : "updating encoding file %s"), filename.c_str());
+        errh->message((ok_retval ? "creating encoding file %s" : "updating encoding file %s"), filename.c_str());
 
     int fd = open(filename.c_str(), O_RDWR | O_CREAT, 0666);
     if (fd < 0)
-	return errh->error("%s: %s", filename.c_str(), strerror(errno));
+        return errh->error("%s: %s", filename.c_str(), strerror(errno));
     f = fdopen(fd, "r+");
     // NB: also change update_autofont_map if you change this code
 
 #if defined(F_SETLKW) && defined(HAVE_FTRUNCATE)
     {
-	struct flock lock;
-	lock.l_type = F_WRLCK;
-	lock.l_whence = SEEK_SET;
-	lock.l_start = 0;
-	lock.l_len = 0;
-	int result;
-	while ((result = fcntl(fd, F_SETLKW, &lock)) < 0 && errno == EINTR)
-	    /* try again */;
-	if (result < 0) {
-	    result = errno;
-	    fclose(f);
-	    return errh->error("locking %s: %s", filename.c_str(), strerror(result));
-	}
+        struct flock lock;
+        lock.l_type = F_WRLCK;
+        lock.l_whence = SEEK_SET;
+        lock.l_start = 0;
+        lock.l_len = 0;
+        int result;
+        while ((result = fcntl(fd, F_SETLKW, &lock)) < 0 && errno == EINTR)
+            /* try again */;
+        if (result < 0) {
+            result = errno;
+            fclose(f);
+            return errh->error("locking %s: %s", filename.c_str(), strerror(result));
+        }
     }
 #endif
 
@@ -996,32 +1008,32 @@ write_encoding_file(String &filename, co
     StringAccum sa;
     int amt;
     do {
-	if (char *x = sa.reserve(8192)) {
-	    amt = fread(x, 1, 8192, f);
-	    sa.adjust_length(amt);
-	} else
-	    amt = 0;
+        if (char *x = sa.reserve(8192)) {
+            amt = fread(x, 1, 8192, f);
+            sa.adjust_length(amt);
+        } else
+            amt = 0;
     } while (amt != 0);
     if (!feof(f) || ferror(f))
-	return errh->error("%s: %s", filename.c_str(), strerror(errno));
+        return errh->error("%s: %s", filename.c_str(), strerror(errno));
     String old_encodings = sa.take_string();
     bool created = (!old_encodings);
 
     // append old encodings
     int pos1 = old_encodings.find_left("\n%%");
     while (pos1 >= 0 && pos1 < old_encodings.length()) {
-	int pos2 = old_encodings.find_left("\n%%", pos1 + 1);
-	if (pos2 < 0)
-	    pos2 = old_encodings.length();
-	if (old_encodings.substring(pos1 + 3, encoding_name.length()) == encoding_name) {
-	    // encoding already exists, don't change it
-	    fclose(f);
-	    if (verbose)
-		errh->message("%s unchanged", filename.c_str());
-	    return 0;
-	} else
-	    contents << old_encodings.substring(pos1, pos2 - pos1);
-	pos1 = pos2;
+        int pos2 = old_encodings.find_left("\n%%", pos1 + 1);
+        if (pos2 < 0)
+            pos2 = old_encodings.length();
+        if (old_encodings.substring(pos1 + 3, encoding_name.length()) == encoding_name) {
+            // encoding already exists, don't change it
+            fclose(f);
+            if (verbose)
+                errh->message("%s unchanged", filename.c_str());
+            return 0;
+        } else
+            contents << old_encodings.substring(pos1, pos2 - pos1);
+        pos1 = pos2;
     }
 
     // rewind file
@@ -1030,9 +1042,9 @@ write_encoding_file(String &filename, co
     if (ftruncate(fd, 0) < 0)
 #endif
     {
-	fclose(f);
-	f = fopen(filename.c_str(), "wb");
-	fd = fileno(f);
+        fclose(f);
+        f = fopen(filename.c_str(), "w");
+        fd = fileno(f);
     }
 
     ignore_result(fwrite(contents.data(), 1, contents.length(), f));
@@ -1041,33 +1053,33 @@ write_encoding_file(String &filename, co
 
     // inform about the new file if necessary
     if (created)
-	update_odir(O_ENCODING, filename, errh);
+        update_odir(O_ENCODING, filename, errh);
     return 0;
 }
 
 static bool
 output_encoding(const Metrics &metrics,
-		const Vector<PermString> &glyph_names,
-		ErrorHandler *errh)
+                const Vector<PermString> &glyph_names,
+                ErrorHandler *errh)
 {
     static const char * const hex_digits = "0123456789ABCDEF";
 
     // collect encoding data
     Vector<Metrics::Glyph> glyphs;
     if (!metrics.base_glyphs(glyphs, 256))
-	return false;
+        return false;
 
     StringAccum sa;
     for (int i = 0; i < 256; i++) {
-	if ((i & 0xF) == 0)
-	    sa << (i ? "\n%" : "%") << hex_digits[(i >> 4) & 0xF] << '0' << '\n' << ' ';
-	else if ((i & 0x7) == 0)
-	    sa << '\n' << ' ';
-	int g = glyphs[i];
-	if (g > 0 && g < glyph_names.size())
-	    sa << ' ' << '/' << glyph_names[g];
-	else
-	    sa << " /.notdef";
+        if ((i & 0xF) == 0)
+            sa << (i ? "\n%" : "%") << hex_digits[(i >> 4) & 0xF] << '0' << '\n' << ' ';
+        else if ((i & 0x7) == 0)
+            sa << '\n' << ' ';
+        int g = glyphs[i];
+        if (g > 0 && g < glyph_names.size())
+            sa << ' ' << '/' << glyph_names[g];
+        else
+            sa << " /.notdef";
     }
     sa << '\n';
 
@@ -1084,18 +1096,18 @@ output_encoding(const Metrics &metrics,
     // create encoding filename
     bool output_encoding_only = (bool) out_encoding_file;
     if (!out_encoding_file)
-	out_encoding_file = getodir(O_ENCODING, errh) + String("/a_") + String(text_digest).substring(0, 6) + ".enc";
+        out_encoding_file = getodir(O_ENCODING, errh) + String("/a_") + String(text_digest).substring(0, 6) + ".enc";
 
     // exit if we're not responsible for generating an encoding
     if (!(output_flags & G_ENCODING))
-	return true;
+        return true;
 
     // put encoding block in a StringAccum
     // 3.Jun.2003: stick command line definition at the end of the encoding,
     // where it won't confuse idiotic ps2pk
     StringAccum contents;
     if (!output_encoding_only)
-	contents << "% THIS FILE WAS AUTOMATICALLY GENERATED -- DO NOT EDIT\n\n\
+        contents << "% THIS FILE WAS AUTOMATICALLY GENERATED -- DO NOT EDIT\n\n\
 %%" << out_encoding_name << "\n";
     contents << "% Encoding created by otftotfm" << current_time << "\n\
 % Command line follows encoding\n";
@@ -1108,156 +1120,199 @@ output_encoding(const Metrics &metrics,
     char *buf = banner.mutable_data();
     // get rid of crap characters
     for (int i = 0; i < banner.length(); i++)
-	if (buf[i] < ' ' || buf[i] > 0176) {
-	    if (buf[i] == '\n' || buf[i] == '\r')
-		buf[i] = ' ';
-	    else
-		buf[i] = '.';
-	}
+        if (buf[i] < ' ' || buf[i] > 0176) {
+            if (buf[i] == '\n' || buf[i] == '\r')
+                buf[i] = ' ';
+            else
+                buf[i] = '.';
+        }
     // break lines at 80 characters -- it would be nice if this were in a
     // library
     while (banner.length() > 0) {
-	int pos = banner.find_left(' '), last_pos = pos;
-	while (pos < 75 && pos >= 0) {
-	    last_pos = pos;
-	    pos = banner.find_left(' ', pos + 1);
-	}
-	if (last_pos < 0 || (pos < 0 && banner.length() < 75))
-	    last_pos = banner.length();
-	contents << "% " << banner.substring(0, last_pos) << '\n';
-	banner = banner.substring(last_pos + 1);
+        int pos = banner.find_left(' '), last_pos = pos;
+        while (pos < 75 && pos >= 0) {
+            last_pos = pos;
+            pos = banner.find_left(' ', pos + 1);
+        }
+        if (last_pos < 0 || (pos < 0 && banner.length() < 75))
+            last_pos = banner.length();
+        contents << "% " << banner.substring(0, last_pos) << '\n';
+        banner = banner.substring(last_pos + 1);
     }
 
     // open encoding file
     if (out_encoding_file == "-")
-	ignore_result(fwrite(contents.data(), 1, contents.length(), stdout));
+        ignore_result(fwrite(contents.data(), 1, contents.length(), stdout));
     else if (write_encoding_file(out_encoding_file, out_encoding_name, contents, errh) == 1)
-	update_odir(O_ENCODING, out_encoding_file, errh);
+        update_odir(O_ENCODING, out_encoding_file, errh);
     return true;
 }
 
 static void
 output_tfm(Metrics &metrics, const String &ps_name, int boundary_char,
-	   const FontInfo &finfo, String tfm_filename, String vf_filename,
-	   ErrorHandler *errh)
+           const FontInfo &finfo, String tfm_filename, String vf_filename,
+           String pl_filename, ErrorHandler *errh)
 {
-    String pl_filename;
+    bool had_pl_filename = !pl_filename.empty();
     bool vpl = vf_filename;
 
-    if (no_create) {
-	errh->message("would write %s to temporary file", (vpl ? "VPL" : "PL"));
-	pl_filename = "<temporary>";
-    } else {
-	int pl_fd = temporary_file(pl_filename, errh);
-	if (pl_fd < 0)
-	    return;
-	output_pl(metrics, ps_name, boundary_char, finfo, vpl, pl_filename, errh);
-	close(pl_fd);
+    if (!pl_filename) {
+        if (no_create) {
+            errh->message("would write %s to temporary file", (vpl ? "VPL" : "PL"));
+            pl_filename = "<temporary>";
+        } else {
+            int pl_fd = temporary_file(pl_filename, errh);
+            if (pl_fd < 0)
+                return;
+            output_pl(metrics, ps_name, boundary_char, finfo, vpl, pl_filename, errh);
+            close(pl_fd);
+        }
     }
 
     StringAccum command;
     if (vpl)
-	command << "vptovf " << shell_quote(pl_filename) << ' ' << shell_quote(vf_filename) << ' ' << shell_quote(tfm_filename) << " >&2";
+        command << "vptovf " << shell_quote(pl_filename) << ' ' << shell_quote(vf_filename) << ' ' << shell_quote(tfm_filename) << " 2>&1";
     else
-	command << "pltotf " << shell_quote(pl_filename) << ' ' << shell_quote(tfm_filename) << " >&2";
+        command << "pltotf " << shell_quote(pl_filename) << ' ' << shell_quote(tfm_filename) << " 2>&1";
 
-    int status = mysystem(command.c_str(), errh);
+    FILE* cmdfile = mypopen(command.c_str(), "r", errh);
+    int status;
+    if (cmdfile) {
+        StringAccum results;
+        while (!feof(cmdfile)) {
+            char* buf = results.reserve(BUFSIZ);
+            results.adjust_length(fread(buf, 1, BUFSIZ, cmdfile));
+        }
+        // compensate for shitty vptovf/pltotf messages
+        char* by_units, *last_line;
+        while (!results.empty()
+               && (by_units = strstr((char*) results.c_str(), "  units"))
+               && (last_line = strrchr((char*) results.c_str(), '\n'))
+               && results.end() - last_line > 1
+               && isdigit((unsigned char) last_line[1])) {
+            char* start_number = last_line + 1;
+            char* end_number = last_line + 2;
+            while (end_number < results.end()
+                   && isdigit((unsigned char) *end_number))
+                ++end_number;
+            if (end_number < results.end() && *end_number == '.') {
+                char* dot = end_number;
+                ++end_number;
+                while (end_number < results.end()
+                       && end_number < dot + 8
+                       && isdigit((unsigned char) *end_number))
+                    ++end_number;
+            }
+            String number(start_number, end_number);
+            char* by_units_dest = by_units + 1 + (end_number - start_number);
+            memmove(by_units_dest, by_units + 1, start_number - (by_units + 1));
+            memmove(by_units + 1, number.begin(), number.length());
+        }
+        if (!results.empty())
+            fwrite(results.begin(), 1, results.length(), stderr);
+        status = pclose(cmdfile);
+    } else
+        status = -1;
 
-    if (!no_create)
-	unlink(pl_filename.c_str());
+    if (!no_create && !had_pl_filename)
+        unlink(pl_filename.c_str());
 
     if (status != 0)
-	errh->fatal("%s execution failed", (vpl ? "vptovf" : "pltotf"));
+        errh->fatal("%s execution failed", (vpl ? "vptovf" : "pltotf"));
     else {
-	update_odir(O_TFM, tfm_filename, errh);
-	if (vpl)
-	    update_odir(O_VF, vf_filename, errh);
+        update_odir(O_TFM, tfm_filename, errh);
+        if (vpl)
+            update_odir(O_VF, vf_filename, errh);
     }
 }
 
 void
 output_metrics(Metrics &metrics, const String &ps_name, int boundary_char,
-	       const FontInfo &finfo,
-	       const String &encoding_name, const String &encoding_file,
-	       const String &font_name,
-	       String (*dvips_include)(const String &ps_name, const FontInfo &, ErrorHandler *),
-	       ErrorHandler *errh)
+               const FontInfo &finfo,
+               const String &encoding_name, const String &encoding_file,
+               const String &font_name,
+               String (*dvips_include)(const String &ps_name, const FontInfo &, ErrorHandler *),
+               ErrorHandler *errh)
 {
     String base_font_name = font_name;
     bool need_virtual = metrics.need_virtual(257);
     if (need_virtual) {
-	if (output_flags & G_VMETRICS)
-	    base_font_name = make_base_font_name(font_name);
-	else if (output_flags & G_METRICS)
-	    errh->warning("features require virtual fonts");
+        if (output_flags & G_VMETRICS)
+            base_font_name = make_base_font_name(font_name);
+        else if (output_flags & G_METRICS)
+            errh->warning("features require virtual fonts");
     }
 
     // output virtual metrics
     if (!(output_flags & G_VMETRICS))
-	/* do nothing */;
+        /* do nothing */;
     else if (!need_virtual) {
-	if (automatic) {
-	    // erase old virtual font
-	    String vf = getodir(O_VF, errh) + "/" + font_name + ".vf";
-	    if (no_create)
-		errh->message("would remove potential VF file %<%s%>", vf.c_str());
-	    else {
-		if (verbose)
-		    errh->message("removing potential VF file %<%s%>", vf.c_str());
-		if (unlink(vf.c_str()) < 0 && errno != ENOENT)
-		    errh->error("removing %s: %s", vf.c_str(), strerror(errno));
-	    }
-	}
+        if (automatic) {
+            // erase old virtual font
+            String vf = getodir(O_VF, errh) + "/" + font_name + ".vf";
+            if (no_create)
+                errh->message("would remove potential VF file %<%s%>", vf.c_str());
+            else {
+                if (verbose)
+                    errh->message("removing potential VF file %<%s%>", vf.c_str());
+                if (unlink(vf.c_str()) < 0 && errno != ENOENT)
+                    errh->error("removing %s: %s", vf.c_str(), strerror(errno));
+            }
+        }
     } else {
-	if (output_flags & G_BINARY) {
-	    String tfm = getodir(O_TFM, errh) + "/" + font_name + ".tfm";
-	    String vf = getodir(O_VF, errh) + "/" + font_name + ".vf";
-	    output_tfm(metrics, ps_name, boundary_char, finfo, tfm, vf, errh);
-	} else {
-	    String outfile = getodir(O_VPL, errh) + "/" + font_name + ".vpl";
-	    output_pl(metrics, ps_name, boundary_char, finfo, true, outfile, errh);
-	    update_odir(O_VPL, outfile, errh);
-	}
+        String vplfile;
+        if (output_flags & G_ASCII) {
+            vplfile = getodir(O_VPL, errh) + "/" + font_name + ".vpl";
+            output_pl(metrics, ps_name, boundary_char, finfo, true, vplfile, errh);
+            update_odir(O_VPL, vplfile, errh);
+        }
+        if (output_flags & G_BINARY) {
+            String tfm = getodir(O_TFM, errh) + "/" + font_name + ".tfm";
+            String vf = getodir(O_VF, errh) + "/" + font_name + ".vf";
+            output_tfm(metrics, ps_name, boundary_char, finfo, tfm, vf, vplfile, errh);
+        }
     }
 
     // quit if no base needed
     metrics.make_base(257);
     if (!metrics.need_base())
-	return;
+        return;
 
     // output metrics
     double save_minimum_kern = minimum_kern;
     if (need_virtual)
-	minimum_kern = 100000;
-    if (!(output_flags & G_METRICS))
-	/* do nothing */;
-    else if (output_flags & G_BINARY) {
-	String tfm = getodir(O_TFM, errh) + "/" + base_font_name + ".tfm";
-	output_tfm(metrics, ps_name, boundary_char, finfo, tfm, String(), errh);
-    } else {
-	String outfile = getodir(O_PL, errh) + "/" + base_font_name + ".pl";
-	output_pl(metrics, ps_name, boundary_char, finfo, false, outfile, errh);
-	update_odir(O_PL, outfile, errh);
+        minimum_kern = 100000;
+    if (output_flags & G_METRICS) {
+        String plfile;
+        if (output_flags & G_ASCII) {
+            plfile = getodir(O_PL, errh) + "/" + base_font_name + ".pl";
+            output_pl(metrics, ps_name, boundary_char, finfo, false, plfile, errh);
+            update_odir(O_PL, plfile, errh);
+        }
+        if (output_flags & G_BINARY) {
+            String tfm = getodir(O_TFM, errh) + "/" + base_font_name + ".tfm";
+            output_tfm(metrics, ps_name, boundary_char, finfo, tfm, String(), plfile, errh);
+        }
     }
     minimum_kern = save_minimum_kern;
 
     // print DVIPS map line
     if (errh->nerrors() == 0 && (output_flags & G_PSFONTSMAP)) {
-	StringAccum sa;
-	sa << base_font_name << ' ' << ps_name << " \"";
-	if (extend)
-	    sa << extend << " ExtendFont ";
-	if (slant)
-	    sa << slant << " SlantFont ";
-	if (encoding_name)
-	    sa << encoding_name << " ReEncodeFont\" <[" << pathname_filename(encoding_file);
-	else
-	    sa << "\"";
-	sa << ' ' << dvips_include(ps_name, finfo, errh) << '\n';
-	update_autofont_map(base_font_name, sa.take_string(), errh);
-	// if virtual font, remove any map line for base font name
-	if (base_font_name != font_name)
-	    update_autofont_map(font_name, "", errh);
+        StringAccum sa;
+        sa << base_font_name << ' ' << ps_name << " \"";
+        if (extend)
+            sa << extend << " ExtendFont ";
+        if (slant)
+            sa << slant << " SlantFont ";
+        if (encoding_name)
+            sa << encoding_name << " ReEncodeFont\" <[" << pathname_filename(encoding_file);
+        else
+            sa << "\"";
+        sa << ' ' << dvips_include(ps_name, finfo, errh) << '\n';
+        update_autofont_map(base_font_name, sa.take_string(), errh);
+        // if virtual font, remove any map line for base font name
+        if (base_font_name != font_name)
+            update_autofont_map(font_name, "", errh);
     }
 }
 
@@ -1281,48 +1336,48 @@ report_underused_features(const HashMap<
 {
     Vector<String> x[X_COUNT];
     for (int i = 0; i < interesting_features.size(); i++) {
-	OpenType::Tag f = interesting_features[i];
-	int fu = feature_usage[f.value()];
-	String ftext = errh->format("%<%s%>", f.text().c_str());
-	if (fu == 0)
-	    x[X_UNUSED].push_back(ftext);
-	else if ((fu & (F_GSUB_TRY | F_GPOS_TRY)) == fu)
-	    x[X_BOTH_NONE].push_back(ftext);
-	else {
-	    if (fu & F_GSUB_TRY) {
-		if ((fu & (F_GSUB_PART | F_GSUB_ALL)) == 0)
-		    x[X_GSUB_NONE].push_back(ftext);
-		else if (fu & F_GSUB_PART)
-		    x[X_GSUB_PART].push_back(ftext);
-	    }
-	    if (fu & F_GPOS_TRY) {
-		if ((fu & (F_GPOS_PART | F_GPOS_ALL)) == 0)
-		    x[X_GPOS_NONE].push_back(ftext);
-		else if (fu & F_GPOS_PART)
-		    x[X_GPOS_PART].push_back(ftext);
-	    }
-	}
+        OpenType::Tag f = interesting_features[i];
+        int fu = feature_usage[f.value()];
+        String ftext = errh->format("%<%s%>", f.text().c_str());
+        if (fu == 0)
+            x[X_UNUSED].push_back(ftext);
+        else if ((fu & (F_GSUB_TRY | F_GPOS_TRY)) == fu)
+            x[X_BOTH_NONE].push_back(ftext);
+        else {
+            if (fu & F_GSUB_TRY) {
+                if ((fu & (F_GSUB_PART | F_GSUB_ALL)) == 0)
+                    x[X_GSUB_NONE].push_back(ftext);
+                else if (fu & F_GSUB_PART)
+                    x[X_GSUB_PART].push_back(ftext);
+            }
+            if (fu & F_GPOS_TRY) {
+                if ((fu & (F_GPOS_PART | F_GPOS_ALL)) == 0)
+                    x[X_GPOS_NONE].push_back(ftext);
+                else if (fu & F_GPOS_PART)
+                    x[X_GPOS_PART].push_back(ftext);
+            }
+        }
     }
 
     for (int i = 0; i < X_COUNT; i++)
-	if (x[i].size())
-	    goto found;
+        if (x[i].size())
+            goto found;
     return;
 
   found:
     for (int i = 0; i < X_COUNT; i++)
-	if (x[i].size()) {
-	    StringAccum sa;
-	    const char* msg_pct = strchr(x_messages[i], '%');
-	    sa.append(x_messages[i], msg_pct - x_messages[i]);
-	    const char* sep = (x[i].size() > 2 ? ", " : " ");
-	    for (const String* a = x[i].begin(); a < x[i].end() - 1; a++)
-		sa << *a << sep;
-	    sa << (x[i].size() > 1 ? "and " : "") << x[i].back()
-	       << (x[i].size() > 1 ? " features" : " feature") << (msg_pct+1);
-	    sa.append_break_lines(sa.take_string(), 58);
-	    errh->warning("%s", sa.c_str());
-	}
+        if (x[i].size()) {
+            StringAccum sa;
+            const char* msg_pct = strchr(x_messages[i], '%');
+            sa.append(x_messages[i], msg_pct - x_messages[i]);
+            const char* sep = (x[i].size() > 2 ? ", " : " ");
+            for (const String* a = x[i].begin(); a < x[i].end() - 1; a++)
+                sa << *a << sep;
+            sa << (x[i].size() > 1 ? "and " : "") << x[i].back()
+               << (x[i].size() > 1 ? " features" : " feature") << (msg_pct+1);
+            sa.append_break_lines(sa.take_string(), 58);
+            errh->warning("%s", sa.c_str());
+        }
 }
 
 static String otf_filename;
@@ -1331,24 +1386,24 @@ static String
 main_dvips_map(const String &ps_name, const FontInfo &finfo, ErrorHandler *errh)
 {
     if (String fn = installed_type1(otf_filename, ps_name, (output_flags & G_TYPE1) != 0, errh))
-	return "<" + pathname_filename(fn);
+        return "<" + pathname_filename(fn);
     if (!finfo.cff) {
-	String ttf_fn, t42_fn;
-	ttf_fn = installed_truetype(otf_filename, (output_flags & G_TRUETYPE) != 0, errh);
-	t42_fn = installed_type42(otf_filename, ps_name, (output_flags & G_TYPE42) != 0, errh);
-	if (t42_fn && (!ttf_fn || (output_flags & G_TYPE42) != 0))
-	    return "<" + pathname_filename(t42_fn);
-	else if (ttf_fn)
-	    return "<" + pathname_filename(ttf_fn);
+        String ttf_fn, t42_fn;
+        ttf_fn = installed_truetype(otf_filename, (output_flags & G_TRUETYPE) != 0, errh);
+        t42_fn = installed_type42(otf_filename, ps_name, (output_flags & G_TYPE42) != 0, errh);
+        if (t42_fn && (!ttf_fn || (output_flags & G_TYPE42) != 0))
+            return "<" + pathname_filename(t42_fn);
+        else if (ttf_fn)
+            return "<" + pathname_filename(ttf_fn);
     }
     return "<" + pathname_filename(otf_filename);
 }
 
 static void
 do_gsub(Metrics& metrics, const OpenType::Font& otf,
-	DvipsEncoding& dvipsenc, bool dvipsenc_literal,
-	HashMap<uint32_t, int>& feature_usage,
-	const Vector<PermString>& glyph_names, ErrorHandler* errh)
+        DvipsEncoding& dvipsenc, bool dvipsenc_literal,
+        HashMap<uint32_t, int>& feature_usage,
+        const Vector<PermString>& glyph_names, ErrorHandler* errh)
 {
     // find activated GSUB features
     OpenType::Gsub gsub(otf.table("GSUB"), &otf, errh);
@@ -1358,70 +1413,70 @@ do_gsub(Metrics& metrics, const OpenType
     // find all characters that might result
     Vector<bool> used(glyph_names.size(), false);
     for (Metrics::Code c = 0; c < metrics.encoding_size(); ++c) {
-	Metrics::Glyph g = metrics.glyph(c);
-	if (g >= 0 && g < used.size())
-	    used[g] = true;
+        Metrics::Glyph g = metrics.glyph(c);
+        if (g >= 0 && g < used.size())
+            used[g] = true;
     }
     for (int i = 0; i < lookups.size(); ++i)
-	if (lookups[i].used) {
-	    OpenType::GsubLookup l = gsub.lookup(i);
-	    l.mark_out_glyphs(gsub, used);
-	}
+        if (lookups[i].used) {
+            OpenType::GsubLookup l = gsub.lookup(i);
+            l.mark_out_glyphs(gsub, used);
+        }
     OpenType::Coverage used_coverage(used);
 
     // apply activated GSUB features
     Vector<OpenType::Substitution> subs;
     for (int i = 0; i < lookups.size(); i++)
-	if (lookups[i].used) {
-	    OpenType::GsubLookup l = gsub.lookup(i);
-	    subs.clear();
-	    bool understood = l.unparse_automatics(gsub, subs, used_coverage);
-
-	    // check for -ffina, which should apply only at the ends of words,
-	    // and -finit, which should apply only at the beginnings.
-	    OpenType::Tag feature = (lookups[i].features.size() == 1 ? lookups[i].features[0] : OpenType::Tag());
-	    if (feature == OpenType::Tag("fina") || feature == OpenType::Tag("fin2") || feature == OpenType::Tag("fin3")) {
-		if (dvipsenc.boundary_char() < 0)
-		    errh->warning("%<-ffina%> requires a boundary character\n(The input encoding didn%,t specify a boundary character, but\nI need one to implement %<-ffina%> features correctly.  Try\nthe %<--boundary-char%> option.)");
-		else {
-		    int bg = metrics.boundary_glyph();
-		    for (int j = 0; j < subs.size(); j++)
-			subs[j].add_outer_right(bg);
-		}
-	    } else if (feature == OpenType::Tag("init")) {
-		int bg = metrics.boundary_glyph();
-		for (int j = 0; j < subs.size(); j++)
-		    subs[j].add_outer_left(bg);
-	    }
-
-	    //for (int subno = 0; subno < subs.size(); subno++) fprintf(stderr, "%5d\t%s\n", i, subs[subno].unparse().c_str());
-
-	    // figure out which glyph filter to use
-	    int nunderstood = metrics.apply(subs, !dvipsenc_literal, i, *lookups[i].filter, glyph_names);
-
-	    // mark as used
-	    int d = (understood && nunderstood == subs.size() ? F_GSUB_ALL : (nunderstood ? F_GSUB_PART : 0)) + F_GSUB_TRY;
-	    for (int j = 0; j < lookups[i].features.size(); j++)
-		feature_usage.find_force(lookups[i].features[j].value()) |= d;
-	}
+        if (lookups[i].used) {
+            OpenType::GsubLookup l = gsub.lookup(i);
+            subs.clear();
+            bool understood = l.unparse_automatics(gsub, subs, used_coverage);
+
+            // check for -ffina, which should apply only at the ends of words,
+            // and -finit, which should apply only at the beginnings.
+            OpenType::Tag feature = (lookups[i].features.size() == 1 ? lookups[i].features[0] : OpenType::Tag());
+            if (feature == OpenType::Tag("fina") || feature == OpenType::Tag("fin2") || feature == OpenType::Tag("fin3")) {
+                if (dvipsenc.boundary_char() < 0)
+                    errh->warning("%<-ffina%> requires a boundary character\n(The input encoding didn%,t specify a boundary character, but\nI need one to implement %<-ffina%> features correctly.  Try\nthe %<--boundary-char%> option.)");
+                else {
+                    int bg = metrics.boundary_glyph();
+                    for (int j = 0; j < subs.size(); j++)
+                        subs[j].add_outer_right(bg);
+                }
+            } else if (feature == OpenType::Tag("init")) {
+                int bg = metrics.boundary_glyph();
+                for (int j = 0; j < subs.size(); j++)
+                    subs[j].add_outer_left(bg);
+            }
+
+            //for (int subno = 0; subno < subs.size(); subno++) fprintf(stderr, "%5d\t%s\n", i, subs[subno].unparse().c_str());
+
+            // figure out which glyph filter to use
+            int nunderstood = metrics.apply(subs, !dvipsenc_literal, i, *lookups[i].filter, glyph_names);
+
+            // mark as used
+            int d = (understood && nunderstood == subs.size() ? F_GSUB_ALL : (nunderstood ? F_GSUB_PART : 0)) + F_GSUB_TRY;
+            for (int j = 0; j < lookups[i].features.size(); j++)
+                feature_usage.find_force(lookups[i].features[j].value()) |= d;
+        }
 
     // apply alternate selectors
     if (metrics.altselectors() && !dvipsenc_literal) {
-	// do lookups
-	altselector_features.swap(interesting_features);
-	altselector_feature_filters.swap(feature_filters);
-	Vector<Lookup> alt_lookups(gsub.nlookups(), Lookup());
-	find_lookups(gsub.script_list(), gsub.feature_list(), alt_lookups, ErrorHandler::silent_handler());
-	Vector<OpenType::Substitution> alt_subs;
-	for (int i = 0; i < alt_lookups.size(); i++)
-	    if (alt_lookups[i].used) {
-		OpenType::GsubLookup l = gsub.lookup(i);
-		alt_subs.clear();
-		(void) l.unparse_automatics(gsub, alt_subs, used_coverage);
-		metrics.apply_alternates(alt_subs, i, *alt_lookups[i].filter, glyph_names);
-	    }
-	altselector_features.swap(interesting_features);
-	altselector_feature_filters.swap(feature_filters);
+        // do lookups
+        altselector_features.swap(interesting_features);
+        altselector_feature_filters.swap(feature_filters);
+        Vector<Lookup> alt_lookups(gsub.nlookups(), Lookup());
+        find_lookups(gsub.script_list(), gsub.feature_list(), alt_lookups, ErrorHandler::silent_handler());
+        Vector<OpenType::Substitution> alt_subs;
+        for (int i = 0; i < alt_lookups.size(); i++)
+            if (alt_lookups[i].used) {
+                OpenType::GsubLookup l = gsub.lookup(i);
+                alt_subs.clear();
+                (void) l.unparse_automatics(gsub, alt_subs, used_coverage);
+                metrics.apply_alternates(alt_subs, i, *alt_lookups[i].filter, glyph_names);
+            }
+        altselector_features.swap(interesting_features);
+        altselector_feature_filters.swap(feature_filters);
     }
 }
 
@@ -1429,7 +1484,7 @@ static bool
 kern_feature_requested()
 {
     return std::find(interesting_features.begin(), interesting_features.end(),
-		     OpenType::Tag("kern")) != interesting_features.end();
+                     OpenType::Tag("kern")) != interesting_features.end();
 }
 
 static void
@@ -1437,20 +1492,20 @@ do_try_ttf_kern(Metrics& metrics, const
 {
     // if no GPOS "kern" lookups and "kern" requested, try "kern" table
     if (!kern_feature_requested())
-	return;
+        return;
     try {
-	OpenType::KernTable kern(otf.table("kern"), errh);
-	Vector<OpenType::Positioning> poss;
-	bool understood = kern.unparse_automatics(poss, errh);
-	int nunderstood = metrics.apply(poss);
-
-	// mark as used
-	int d = (understood && nunderstood == poss.size() ? F_GPOS_ALL : (nunderstood ? F_GPOS_PART : 0)) + F_GPOS_TRY;
-	feature_usage.find_force(OpenType::Tag("kern").value()) |= d;
+        OpenType::KernTable kern(otf.table("kern"), errh);
+        Vector<OpenType::Positioning> poss;
+        bool understood = kern.unparse_automatics(poss, errh);
+        int nunderstood = metrics.apply(poss);
+
+        // mark as used
+        int d = (understood && nunderstood == poss.size() ? F_GPOS_ALL : (nunderstood ? F_GPOS_PART : 0)) + F_GPOS_TRY;
+        feature_usage.find_force(OpenType::Tag("kern").value()) |= d;
     } catch (OpenType::BlankTable) {
-	// nada
+        // nada
     } catch (OpenType::Error e) {
-	errh->warning("kern %<%s%> error, continuing", e.description.c_str());
+        errh->warning("kern %<%s%> error, continuing", e.description.c_str());
     }
 }
 
@@ -1464,77 +1519,78 @@ do_gpos(Metrics& metrics, const OpenType
     // OpenType recommends that if GPOS exists, but the "kern" feature loads
     // no lookups, we use the TrueType "kern" table, if any.
     if (kern_feature_requested()) {
-	OpenType::Tag kern_tag("kern");
-	for (Lookup *l = lookups.begin(); l != lookups.end(); ++l)
-	    if (std::find(l->features.begin(), l->features.end(), kern_tag) != l->features.end())
-		goto skip_ttf_kern;
-	do_try_ttf_kern(metrics, otf, feature_usage, errh);
+        OpenType::Tag kern_tag("kern");
+        for (Lookup *l = lookups.begin(); l != lookups.end(); ++l)
+            if (std::find(l->features.begin(), l->features.end(), kern_tag) != l->features.end())
+                goto skip_ttf_kern;
+        do_try_ttf_kern(metrics, otf, feature_usage, errh);
     skip_ttf_kern: ;
     }
 
     Vector<OpenType::Positioning> poss;
     for (int i = 0; i < lookups.size(); i++)
-	if (lookups[i].used) {
-	    OpenType::GposLookup l = gpos.lookup(i);
-	    poss.clear();
-	    bool understood = l.unparse_automatics(poss, errh);
-	    int nunderstood = metrics.apply(poss);
-
-	    // mark as used
-	    int d = (understood && nunderstood == poss.size() ? F_GPOS_ALL : (nunderstood ? F_GPOS_PART : 0)) + F_GPOS_TRY;
-	    for (int j = 0; j < lookups[i].features.size(); j++)
-		feature_usage.find_force(lookups[i].features[j].value()) |= d;
-	}
+        if (lookups[i].used) {
+            OpenType::GposLookup l = gpos.lookup(i);
+            poss.clear();
+            bool understood = l.unparse_automatics(poss, errh);
+            int nunderstood = metrics.apply(poss);
+
+            // mark as used
+            int d = (understood && nunderstood == poss.size() ? F_GPOS_ALL : (nunderstood ? F_GPOS_PART : 0)) + F_GPOS_TRY;
+            for (int j = 0; j < lookups[i].features.size(); j++)
+                feature_usage.find_force(lookups[i].features[j].value()) |= d;
+        }
 }
 
 static void
 do_math_spacing(Metrics &metrics, const FontInfo &finfo,
-		const DvipsEncoding &dvipsenc)
+                const DvipsEncoding &dvipsenc)
 {
     Transform font_xform;
     if (extend)
-	font_xform.scale(extend, 1);
+        font_xform.scale(extend, 1);
     if (slant)
-	font_xform.shear(slant);
+        font_xform.shear(slant);
     CharstringBounds boundser(font_xform);
 
     double x_height = finfo.x_height(font_xform);
-    double slant = font_slant(finfo);
+    double actual_slant = font_slant(finfo);
     int boundary_char = dvipsenc.boundary_char();
 
     double bounds[4], width;
 
     for (int code = 0; code < metrics.encoding_size(); code++)
-	if (metrics.was_base_glyph(code) && code != boundary_char
-	    && char_bounds(bounds, width, finfo, font_xform, code)) {
-	    int left_sb = (bounds[0] < 0 ? (int) ceil(-bounds[0]) : 0);
-	    metrics.add_single_positioning(code, left_sb, 0, left_sb);
-
-	    if (skew_char >= 0 && code < 256) {
-		double virtual_height =
-                    (bounds[3] > x_height ? bounds[3] : x_height)
-                    - 0.5 * x_height;
-		double right_sb = (bounds[2] > width ? bounds[2] - width : 0);
-		int skew = (int) (slant * virtual_height + left_sb - right_sb);
-		metrics.add_kern(code, skew_char, skew);
-	    }
-	}
+        if (metrics.was_base_glyph(code)
+            && code != boundary_char
+            && char_bounds(bounds, width, finfo, font_xform, metrics.unicode(code))) {
+            int left_sb = (bounds[0] < 0 ? (int) ceil(-bounds[0]) : 0);
+            metrics.add_single_positioning(code, left_sb, 0, left_sb);
+
+            if (skew_char >= 0 && code < 256) {
+                double sheight = std::max(bounds[3], x_height) - 0.5 * x_height;
+                double right_sb = std::max(bounds[2] - width, 0.0);
+                double desired = left_sb + 0.5 * width + actual_slant * sheight + 0.25 * right_sb;
+                double computed = 0.5 * (left_sb + width + right_sb);
+                int skew = (int) (desired - computed);
+                metrics.add_kern(code, skew_char, skew);
+            }
+        }
 }
 
 static void
 do_file(const String &otf_filename, const OpenType::Font &otf,
-	const DvipsEncoding &dvipsenc_in, bool dvipsenc_literal,
-	ErrorHandler *errh)
+        const DvipsEncoding &dvipsenc_in, bool dvipsenc_literal,
+        ErrorHandler *errh)
 {
     FontInfo finfo(&otf, errh);
     if (!finfo.ok())
-	return;
+        return;
     if (!finfo.cff)
-	errh->warning("TrueType-flavored font support is experimental");
+        errh->warning("TrueType-flavored font support is experimental");
     if (override_is_fixed_pitch)
-	finfo.set_is_fixed_pitch(is_fixed_pitch);
+        finfo.set_is_fixed_pitch(is_fixed_pitch);
     if (override_italic_angle)
-	finfo.set_italic_angle(italic_angle);
+        finfo.set_italic_angle(italic_angle);
     if (override_x_height != FontInfo::x_height_auto)
         finfo.set_x_height(override_x_height, x_height);
 
@@ -1545,15 +1601,15 @@ do_file(const String &otf_filename, cons
 
     // set typeface name from font family name
     {
-	String typeface = finfo.family_name();
+        String typeface = finfo.family_name();
 
-	// make it reasonable for the shell
-	StringAccum sa;
-	for (int i = 0; i < typeface.length(); i++)
-	    if (isalnum((unsigned char) typeface[i]) || typeface[i] == '_' || typeface[i] == '-' || typeface[i] == '.' || typeface[i] == ',' || typeface[i] == '+')
-		sa << typeface[i];
+        // make it reasonable for the shell
+        StringAccum sa;
+        for (int i = 0; i < typeface.length(); i++)
+            if (isalnum((unsigned char) typeface[i]) || typeface[i] == '_' || typeface[i] == '-' || typeface[i] == '.' || typeface[i] == ',' || typeface[i] == '+')
+                sa << typeface[i];
 
-	set_typeface(sa.length() ? sa.take_string() : font_name, false);
+        set_typeface(sa.length() ? sa.take_string() : font_name, false);
     }
 
     // initialize encoding
@@ -1562,10 +1618,10 @@ do_file(const String &otf_filename, cons
     // encode boundary glyph at 256; pretend its Unicode value is '\n'
     metrics.encode(256, '\n', metrics.boundary_glyph());
     if (dvipsenc_literal)
-	dvipsenc.make_metrics(metrics, finfo, 0, true, errh);
+        dvipsenc.make_metrics(metrics, finfo, 0, true, errh);
     else {
-	T1Secondary secondary(finfo, font_name, otf_filename);
-	dvipsenc.make_metrics(metrics, finfo, &secondary, false, errh);
+        T1Secondary secondary(finfo, font_name, otf_filename);
+        dvipsenc.make_metrics(metrics, finfo, &secondary, false, errh);
     }
 
     // maintain statistics about features
@@ -1573,11 +1629,11 @@ do_file(const String &otf_filename, cons
 
     // apply activated GSUB features
     try {
-	do_gsub(metrics, otf, dvipsenc, dvipsenc_literal, feature_usage, glyph_names, errh);
+        do_gsub(metrics, otf, dvipsenc, dvipsenc_literal, feature_usage, glyph_names, errh);
     } catch (OpenType::BlankTable) {
-	// nada
+        // nada
     } catch (OpenType::Error e) {
-	errh->warning("GSUB %<%s%> error, continuing", e.description.c_str());
+        errh->warning("GSUB %<%s%> error, continuing", e.description.c_str());
     }
 
     // apply LIGKERN ligature commands to the result
@@ -1588,15 +1644,15 @@ do_file(const String &otf_filename, cons
 
     // reencode characters to fit within 8 bytes (+ 1 for the boundary)
     if (!dvipsenc_literal)
-	metrics.shrink_encoding(257, dvipsenc_in, errh);
+        metrics.shrink_encoding(257, dvipsenc_in, errh);
 
     // apply activated GPOS features
     try {
-	do_gpos(metrics, otf, feature_usage, errh);
+        do_gpos(metrics, otf, feature_usage, errh);
     } catch (OpenType::BlankTable) {
-	do_try_ttf_kern(metrics, otf, feature_usage, errh);
+        do_try_ttf_kern(metrics, otf, feature_usage, errh);
     } catch (OpenType::Error e) {
-	errh->warning("GPOS %<%s%> error, continuing", e.description.c_str());
+        errh->warning("GPOS %<%s%> error, continuing", e.description.c_str());
     }
 
     // apply LIGKERN kerning and POS positioning commands to the result
@@ -1605,11 +1661,11 @@ do_file(const String &otf_filename, cons
 
     // use prespecified raw fonts
     for (BaseEncoding **be = base_encodings.begin(); be != base_encodings.end(); be++)
-	if (!(*be)->secondary) {
-	    Vector<int> mapp;
-	    (*be)->encoding.make_base_mappings(mapp, finfo);
-	    metrics.apply_base_encoding((*be)->font_name, (*be)->encoding, mapp);
-	}
+        if (!(*be)->secondary) {
+            Vector<int> mapp;
+            (*be)->encoding.make_base_mappings(mapp, finfo);
+            metrics.apply_base_encoding((*be)->font_name, (*be)->encoding, mapp);
+        }
 
     // remove extra characters
     metrics.cut_encoding(257);
@@ -1618,24 +1674,24 @@ do_file(const String &otf_filename, cons
 
     // apply letterspacing, if any
     if (letterspace)
-	for (int code = 0; code < metrics.encoding_size(); code++)
-	    if (metrics.was_base_glyph(code) && code != boundary_char) {
-		metrics.add_single_positioning(code, letterspace / 2, 0, letterspace);
-		if (code < 256) {
-		    metrics.add_kern(code, 256, -letterspace / 2);
-		    metrics.add_kern(256, code, -letterspace / 2);
-		}
-	    }
+        for (int code = 0; code < metrics.encoding_size(); code++)
+            if (metrics.was_base_glyph(code) && code != boundary_char) {
+                metrics.add_single_positioning(code, letterspace / 2, 0, letterspace);
+                if (code < 256) {
+                    metrics.add_kern(code, 256, -letterspace / 2);
+                    metrics.add_kern(256, code, -letterspace / 2);
+                }
+            }
 
     // apply math letterspacing, if any
     if (math_spacing)
-	do_math_spacing(metrics, finfo, dvipsenc);
+        do_math_spacing(metrics, finfo, dvipsenc);
 
     // reencode right components of boundary_glyph as boundary_char
     if (metrics.reencode_right_ligkern(256, boundary_char) > 0
-	&& boundary_char < 0) {
-	errh->warning("no boundary character, ignoring some ligatures and/or kerns\n");
-	errh->message("(You may want to try the --boundary-char option.)");
+        && boundary_char < 0) {
+        errh->warning("no boundary character, ignoring some ligatures and/or kerns\n");
+        errh->message("(You may want to try the --boundary-char option.)");
     }
 
     // report unused and underused features if any
@@ -1643,51 +1699,51 @@ do_file(const String &otf_filename, cons
 
     // figure out our FONTNAME
     if (!font_name) {
-	// derive font name from OpenType font name
-	font_name = finfo.postscript_name();
-	if (encoding_file) {
-	    int slash = encoding_file.find_right('/') + 1;
-	    int dot = encoding_file.find_right('.');
-	    if (dot < slash)	// includes dot < 0 case
-		dot = encoding_file.length();
-	    font_name += String("--") + encoding_file.substring(slash, dot - slash);
-	}
-	if (interesting_scripts.size() != 2 || interesting_scripts[0] != OpenType::Tag("latn") || interesting_scripts[1].valid())
-	    for (int i = 0; i < interesting_scripts.size(); i += 2) {
-		font_name += String("--S") + interesting_scripts[i].text();
-		if (interesting_scripts[i+1].valid())
-		    font_name += String(".") + interesting_scripts[i+1].text();
-	    }
-	for (int i = 0; i < interesting_features.size(); i++)
-	    if (feature_usage[interesting_features[i].value()])
-		font_name += String("--F") + interesting_features[i].text();
+        // derive font name from OpenType font name
+        font_name = finfo.postscript_name();
+        if (encoding_file) {
+            int slash = encoding_file.find_right('/') + 1;
+            int dot = encoding_file.find_right('.');
+            if (dot < slash)    // includes dot < 0 case
+                dot = encoding_file.length();
+            font_name += String("--") + encoding_file.substring(slash, dot - slash);
+        }
+        if (interesting_scripts.size() != 2 || interesting_scripts[0] != OpenType::Tag("latn") || interesting_scripts[1].valid())
+            for (int i = 0; i < interesting_scripts.size(); i += 2) {
+                font_name += String("--S") + interesting_scripts[i].text();
+                if (interesting_scripts[i+1].valid())
+                    font_name += String(".") + interesting_scripts[i+1].text();
+            }
+        for (int i = 0; i < interesting_features.size(); i++)
+            if (feature_usage[interesting_features[i].value()])
+                font_name += String("--F") + interesting_features[i].text();
     }
 
     // output encoding
     if (dvipsenc_literal) {
-	out_encoding_name = dvipsenc_in.name();
-	out_encoding_file = dvipsenc_in.filename();
+        out_encoding_name = dvipsenc_in.name();
+        out_encoding_file = dvipsenc_in.filename();
     } else
-	output_encoding(metrics, glyph_names, errh);
+        output_encoding(metrics, glyph_names, errh);
 
     // set up coding scheme
     if (metrics.coding_scheme())
-	metrics.set_design_units(1);
+        metrics.set_design_units(1);
     else
-	metrics.set_coding_scheme(out_encoding_name);
+        metrics.set_coding_scheme(out_encoding_name);
 
     // force no type 1
     if (!finfo.cff && (output_flags & G_TYPE1)) {
-	errh->warning("assuming --no-type1 since this font is TrueType-flavored");
-	output_flags &= ~G_TYPE1;
+        errh->warning("assuming --no-type1 since this font is TrueType-flavored");
+        output_flags &= ~G_TYPE1;
     }
 
     // output
     ::otf_filename = otf_filename;
     output_metrics(metrics, finfo.postscript_name(), dvipsenc.boundary_char(),
-		   finfo,
-		   out_encoding_name, out_encoding_file,
-		   font_name, main_dvips_map, errh);
+                   finfo,
+                   out_encoding_name, out_encoding_file,
+                   font_name, main_dvips_map, errh);
 }
 
 
@@ -1695,8 +1751,8 @@ String
 installed_metrics_font_name(const String &base_font_name, const String &secondary)
 {
     for (BaseEncoding **be = base_encodings.begin(); be != base_encodings.end(); be++)
-	if ((*be)->secondary == secondary && ::font_name == base_font_name)
-	    return (*be)->font_name;
+        if ((*be)->secondary == secondary && ::font_name == base_font_name)
+            return (*be)->font_name;
     return String();
 }
 
@@ -1706,16 +1762,16 @@ static int
 clp_parse_char(Clp_Parser *clp, const char *arg, int complain, void *)
 {
     if (arg[0] && !arg[1] && !isdigit((unsigned char) arg[0])) {
-	clp->val.i = (unsigned char)arg[0];
-	return 1;
+        clp->val.i = (unsigned char)arg[0];
+        return 1;
     } else if (arg[0] == '-' || isdigit((unsigned char) arg[0])) {
-	char *end;
-	clp->val.i = strtol(arg, &end, 10);
-	if (clp->val.i <= 255 && !*end)
-	    return 1;
+        char *end;
+        clp->val.i = strtol(arg, &end, 10);
+        if (clp->val.i <= 255 && !*end)
+            return 1;
     }
     if (complain)
-	Clp_OptionError(clp, "'%O' expects a character, not '%s'", arg);
+        Clp_OptionError(clp, "'%O' expects a character, not '%s'", arg);
     return 0;
 }
 }
@@ -1729,51 +1785,51 @@ parse_base_encodings(const String &filen
     str.c_str();
     const char *s_end = str.end();
     for (const char *s = str.begin(); s != s_end; ) {
-	while (s != s_end && isspace((unsigned char) *s) && *s != '\n' && *s != '\r')
-	    s++;
-	// skip comments and blank lines
-	if (s != s_end && *s != '%' && *s != '#' && *s != '\n' && *s != '\r') {
-	    const char *w1 = s;
-	    while (s != s_end && !isspace((unsigned char) *s))
-		s++;
-	    BaseEncoding *be = new BaseEncoding;
-	    be->font_name = str.substring(w1, s);
-	    while (s != s_end && isspace((unsigned char) *s) && *s != '\n' && *s != '\r')
-		s++;
-	    const char *w2 = s;
-	    while (s != s_end && !isspace((unsigned char) *s))
-		s++;
-	    String efile = str.substring(w2, s);
-	    while (s != s_end && isspace((unsigned char) *s) && *s != '\n' && *s != '\r')
-		s++;
-	    if (s != s_end && !isspace((unsigned char) *s) && *s != '%' && *s != '#') {
-		const char *w3 = s;
-		while (s != s_end && !isspace((unsigned char) *s))
-		    s++;
-		be->secondary = str.substring(w3, s);
-	    }
-	    LandmarkErrorHandler lerrh(errh, print_filename + String(lineno));
-	    int before = lerrh.nerrors();
-	    if (be->secondary)
-		/* encoding ignored */;
-	    else if (!efile)
-		lerrh.error("missing encoding name");
-	    else if (String path = locate_encoding(efile, errh))
-		be->encoding.parse(path, true, true, &lerrh);
-	    else
-		lerrh.error("encoding %<%s%> not found", efile.c_str());
-	    if (lerrh.nerrors() == before)
-		base_encodings.push_back(be);
-	    else
-		delete be;
-	}
-	while (s != s_end && *s != '\n' && *s != '\r')
-	    s++;
-	if (s != s_end && *s == '\r')
-	    s++;
-	if (s != s_end && *s == '\n')
-	    s++;
-	lineno++;
+        while (s != s_end && isspace((unsigned char) *s) && *s != '\n' && *s != '\r')
+            s++;
+        // skip comments and blank lines
+        if (s != s_end && *s != '%' && *s != '#' && *s != '\n' && *s != '\r') {
+            const char *w1 = s;
+            while (s != s_end && !isspace((unsigned char) *s))
+                s++;
+            BaseEncoding *be = new BaseEncoding;
+            be->font_name = str.substring(w1, s);
+            while (s != s_end && isspace((unsigned char) *s) && *s != '\n' && *s != '\r')
+                s++;
+            const char *w2 = s;
+            while (s != s_end && !isspace((unsigned char) *s))
+                s++;
+            String efile = str.substring(w2, s);
+            while (s != s_end && isspace((unsigned char) *s) && *s != '\n' && *s != '\r')
+                s++;
+            if (s != s_end && !isspace((unsigned char) *s) && *s != '%' && *s != '#') {
+                const char *w3 = s;
+                while (s != s_end && !isspace((unsigned char) *s))
+                    s++;
+                be->secondary = str.substring(w3, s);
+            }
+            LandmarkErrorHandler lerrh(errh, print_filename + String(lineno));
+            int before = lerrh.nerrors();
+            if (be->secondary)
+                /* encoding ignored */;
+            else if (!efile)
+                lerrh.error("missing encoding name");
+            else if (String path = locate_encoding(efile, errh))
+                be->encoding.parse(path, true, true, &lerrh);
+            else
+                lerrh.error("encoding %<%s%> not found", efile.c_str());
+            if (lerrh.nerrors() == before)
+                base_encodings.push_back(be);
+            else
+                delete be;
+        }
+        while (s != s_end && *s != '\n' && *s != '\r')
+            s++;
+        if (s != s_end && *s == '\r')
+            s++;
+        if (s != s_end && *s == '\n')
+            s++;
+        lineno++;
     }
 }
 
@@ -1784,7 +1840,7 @@ main(int argc, char *argv[])
     handle_sigchld();
 #endif
     Clp_Parser *clp =
-	Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options);
+        Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options);
     Clp_AddType(clp, CHAR_OPTTYPE, 0, clp_parse_char, 0);
     program_name = Clp_ProgramName(clp);
 #if HAVE_KPATHSEA
@@ -1792,13 +1848,13 @@ main(int argc, char *argv[])
 #endif
 #ifdef HAVE_CTIME
     {
-	time_t t = time(0);
-	char *c = ctime(&t);
-	current_time = " on " + String(c).substring(0, -1); // get rid of \n
+        time_t t = time(0);
+        char *c = ctime(&t);
+        current_time = " on " + String(c).substring(0, -1); // get rid of \n
     }
 #endif
     for (int i = 0; i < argc; i++)
-	invocation << (i ? " " : "") << argv[i];
+        invocation << (i ? " " : "") << argv[i];
 
     ErrorHandler *errh = ErrorHandler::static_initialize(new FileErrorHandler(stderr, String(program_name) + ": "));
     const char *input_file = 0;
@@ -1811,350 +1867,376 @@ main(int argc, char *argv[])
     Vector<String> base_encoding_files;
     bool no_ecommand = false, default_ligkern = true;
     int warn_missing = -1;
+    unsigned specified_output_flags = 0;
     String codingscheme;
+    const char* odirs[NUMODIR + 1];
+    for (int i = 0; i <= NUMODIR; ++i) {
+        odirs[i] = 0;
+    }
 
     GlyphFilter current_substitution_filter;
     GlyphFilter current_alternate_filter;
     GlyphFilter* current_filter_ptr = &null_filter;
+    Vector<GlyphFilter*> allocated_filters;
 
     while (1) {
-	int opt = Clp_Next(clp);
-	switch (opt) {
+        int opt = Clp_Next(clp);
+        switch (opt) {
 
-	  case SCRIPT_OPT: {
-	      String arg = clp->vstr;
-	      int period = arg.find_left('.');
-	      OpenType::Tag scr(period <= 0 ? arg : arg.substring(0, period));
-	      if (scr.valid() && period > 0) {
-		  OpenType::Tag lang(arg.substring(period + 1));
-		  if (lang.valid()) {
-		      interesting_scripts.push_back(scr);
-		      interesting_scripts.push_back(lang);
-		  } else
-		      usage_error(errh, "bad language tag");
-	      } else if (scr.valid()) {
-		  interesting_scripts.push_back(scr);
-		  interesting_scripts.push_back(OpenType::Tag());
-	      } else
-		  usage_error(errh, "bad script tag");
-	      break;
-	  }
-
-	  case FEATURE_OPT: {
-	      OpenType::Tag t(clp->vstr);
-	      if (!t.valid())
-		  usage_error(errh, "bad feature tag");
-	      else if (feature_filters[t])
-		  usage_error(errh, "feature %<%s%> included twice", t.text().c_str());
-	      else {
-		  if (!current_filter_ptr)
-		      current_filter_ptr = new GlyphFilter(current_substitution_filter + current_alternate_filter);
-		  interesting_features.push_back(t);
-		  feature_filters.insert(t, current_filter_ptr);
-	      }
-	      break;
-	  }
-
-	  case LETTER_FEATURE_OPT: {
-	      OpenType::Tag t(clp->vstr);
-	      if (!t.valid())
-		  usage_error(errh, "bad feature tag");
-	      else if (feature_filters[t])
-		  usage_error(errh, "feature %<%s%> included twice", t.text().c_str());
-	      else {
-		  interesting_features.push_back(t);
-		  GlyphFilter* gf = new GlyphFilter;
-		  gf->add_substitution_filter("<Letter>", false, errh);
-		  *gf += current_alternate_filter;
-		  feature_filters.insert(t, gf);
-	      }
-	      break;
-	  }
-
-	  case SUBS_FILTER_OPT:
-	    current_substitution_filter = null_filter;
-	    /* fallthru */
-	  case EXCLUDE_SUBS_OPT:
-	  case INCLUDE_SUBS_OPT:
-	    current_substitution_filter.add_substitution_filter(clp->vstr, opt == EXCLUDE_SUBS_OPT, errh);
-	    current_filter_ptr = 0;
-	    break;
-
-	  case CLEAR_SUBS_OPT:
-	    current_substitution_filter = null_filter;
-	    current_filter_ptr = 0;
-	    break;
-
-	  case ENCODING_OPT:
-	    if (encoding_file)
-		usage_error(errh, "encoding specified twice");
-	    encoding_file = clp->vstr;
+          case SCRIPT_OPT: {
+              String arg = clp->vstr;
+              int period = arg.find_left('.');
+              OpenType::Tag scr(period <= 0 ? arg : arg.substring(0, period));
+              if (scr.valid() && period > 0) {
+                  OpenType::Tag lang(arg.substring(period + 1));
+                  if (lang.valid()) {
+                      interesting_scripts.push_back(scr);
+                      interesting_scripts.push_back(lang);
+                  } else
+                      usage_error(errh, "bad language tag");
+              } else if (scr.valid()) {
+                  interesting_scripts.push_back(scr);
+                  interesting_scripts.push_back(OpenType::Tag());
+              } else
+                  usage_error(errh, "bad script tag");
+              break;
+          }
+
+          case FEATURE_OPT: {
+              OpenType::Tag t(clp->vstr);
+              if (!t.valid())
+                  usage_error(errh, "bad feature tag");
+              else if (feature_filters[t])
+                  usage_error(errh, "feature %<%s%> included twice", t.text().c_str());
+              else {
+                  if (!current_filter_ptr) {
+                      current_filter_ptr = new GlyphFilter(current_substitution_filter + current_alternate_filter);
+                      allocated_filters.push_back(current_filter_ptr);
+                  }
+                  interesting_features.push_back(t);
+                  feature_filters.insert(t, current_filter_ptr);
+              }
+              break;
+          }
+
+          case LETTER_FEATURE_OPT: {
+              OpenType::Tag t(clp->vstr);
+              if (!t.valid())
+                  usage_error(errh, "bad feature tag");
+              else if (feature_filters[t])
+                  usage_error(errh, "feature %<%s%> included twice", t.text().c_str());
+              else {
+                  interesting_features.push_back(t);
+                  GlyphFilter* gf = new GlyphFilter;
+                  gf->add_substitution_filter("<Letter>", false, errh);
+                  *gf += current_alternate_filter;
+                  feature_filters.insert(t, gf);
+              }
+              break;
+          }
+
+          case SUBS_FILTER_OPT:
+            current_substitution_filter = null_filter;
+            /* fallthru */
+          case EXCLUDE_SUBS_OPT:
+          case INCLUDE_SUBS_OPT:
+            current_substitution_filter.add_substitution_filter(clp->vstr, opt == EXCLUDE_SUBS_OPT, errh);
+            current_filter_ptr = 0;
+            break;
+
+          case CLEAR_SUBS_OPT:
+            current_substitution_filter = null_filter;
+            current_filter_ptr = 0;
+            break;
+
+          case ENCODING_OPT:
+            if (encoding_file)
+                usage_error(errh, "encoding specified twice");
+            encoding_file = clp->vstr;
             have_encoding_file = true;
-	    break;
+            break;
 
-	  case LITERAL_ENCODING_OPT:
-	    if (encoding_file)
-		usage_error(errh, "encoding specified twice");
-	    encoding_file = clp->vstr;
+          case LITERAL_ENCODING_OPT:
+            if (encoding_file)
+                usage_error(errh, "encoding specified twice");
+            encoding_file = clp->vstr;
             have_encoding_file = true;
-	    literal_encoding = true;
-	    break;
+            literal_encoding = true;
+            break;
+
+          case BASE_ENCODINGS_OPT:
+            base_encoding_files.push_back(clp->vstr);
+            break;
+
+          case EXTEND_OPT:
+            if (extend)
+                usage_error(errh, "extend value specified twice");
+            extend = clp->val.d;
+            break;
+
+          case SLANT_OPT:
+            if (slant)
+                usage_error(errh, "slant value specified twice");
+            slant = clp->val.d;
+            break;
+
+          case LETTERSPACE_OPT:
+            if (letterspace)
+                usage_error(errh, "letterspacing value specified twice");
+            letterspace = clp->val.i;
+            break;
+
+          case SPACE_FACTOR_OPT:
+            if (space_factor != 1)
+                usage_error(errh, "space factor specified twice");
+            space_factor = clp->val.d;
+            break;
+
+          case MATH_SPACING_OPT:
+            math_spacing = !clp->negated;
+            if (math_spacing && clp->have_val) {
+                if (clp->val.i < 0 || clp->val.i > 255)
+                    usage_error(errh, "--math-spacing skew character must be between 0 and 255");
+                skew_char = clp->val.i;
+            }
+            break;
+
+          case DESIGN_SIZE_OPT:
+            if (design_size > 0)
+                usage_error(errh, "design size value specified twice");
+            else if (clp->val.d <= 0)
+                usage_error(errh, "design size must be > 0");
+            design_size = clp->val.d;
+            break;
+
+          case LIGKERN_OPT:
+            ligkern.push_back(clp->vstr);
+            break;
+
+          case POSITION_OPT:
+            pos.push_back(clp->vstr);
+            break;
+
+          case WARN_MISSING_OPT:
+            warn_missing = !clp->negated;
+            break;
+
+          case NO_ECOMMAND_OPT:
+            no_ecommand = true;
+            break;
+
+          case DEFAULT_LIGKERN_OPT:
+            default_ligkern = !clp->negated;
+            break;
+
+          case BOUNDARY_CHAR_OPT:
+            ligkern.push_back(String("|| = ") + String(clp->val.i));
+            break;
+
+          case ALTSELECTOR_CHAR_OPT:
+            ligkern.push_back(String("^^ = ") + String(clp->val.i));
+            break;
+
+          case ALTSELECTOR_FEATURE_OPT: {
+              OpenType::Tag t(clp->vstr);
+              if (!t.valid())
+                  usage_error(errh, "bad feature tag");
+              else if (altselector_feature_filters[t])
+                  usage_error(errh, "altselector feature %<%s%> included twice", t.text().c_str());
+              else {
+                  if (!current_filter_ptr) {
+                      current_filter_ptr = new GlyphFilter(current_substitution_filter + current_alternate_filter);
+                      allocated_filters.push_back(current_filter_ptr);
+                  }
+                  altselector_features.push_back(t);
+                  altselector_feature_filters.insert(t, current_filter_ptr);
+              }
+              break;
+          }
+
+          case ALTERNATES_FILTER_OPT:
+            current_alternate_filter = null_filter;
+            /* fallthru */
+          case EXCLUDE_ALTERNATES_OPT:
+          case INCLUDE_ALTERNATES_OPT:
+            current_alternate_filter.add_alternate_filter(clp->vstr, opt == EXCLUDE_ALTERNATES_OPT, errh);
+            current_filter_ptr = 0;
+            break;
+
+          case CLEAR_ALTERNATES_OPT:
+            current_alternate_filter = null_filter;
+            current_filter_ptr = 0;
+            break;
+
+          case UNICODING_OPT:
+            unicoding.push_back(clp->vstr);
+            break;
+
+          case CODINGSCHEME_OPT:
+            if (codingscheme)
+                usage_error(errh, "coding scheme specified twice");
+            codingscheme = clp->vstr;
+            if (codingscheme.length() > 39)
+                errh->warning("only first 39 characters of coding scheme are significant");
+            if (codingscheme.find_left('(') >= 0 || codingscheme.find_left(')') >= 0)
+                usage_error(errh, "coding scheme cannot contain parentheses");
+            break;
+
+          case AUTOMATIC_OPT:
+            automatic = !clp->negated;
+            break;
+
+          case VENDOR_OPT:
+            if (!set_vendor(clp->vstr))
+                usage_error(errh, "vendor name specified twice");
+            break;
+
+          case TYPEFACE_OPT:
+            if (!set_typeface(clp->vstr, true))
+                usage_error(errh, "typeface name specified twice");
+            break;
+
+          case VIRTUAL_OPT:
+            if (clp->negated)
+                output_flags &= ~G_VMETRICS;
+            else
+                output_flags |= G_VMETRICS;
+            specified_output_flags |= G_VMETRICS;
+            break;
+
+        case NO_ENCODING_OPT:
+        case NO_TYPE1_OPT:
+        case NO_DOTLESSJ_OPT:
+        case NO_UPDMAP_OPT:
+            output_flags &= ~(opt - NO_OUTPUT_OPTS);
+            specified_output_flags |= opt - NO_OUTPUT_OPTS;
+            break;
+
+        case TRUETYPE_OPT:
+        case TYPE42_OPT:
+            if (!clp->negated)
+                output_flags |= (opt - YES_OUTPUT_OPTS);
+            else
+                output_flags &= ~(opt - YES_OUTPUT_OPTS);
+            specified_output_flags |= opt - YES_OUTPUT_OPTS;
+            break;
 
-	  case BASE_ENCODINGS_OPT:
-	    base_encoding_files.push_back(clp->vstr);
-	    break;
-
-	  case EXTEND_OPT:
-	    if (extend)
-		usage_error(errh, "extend value specified twice");
-	    extend = clp->val.d;
-	    break;
-
-	  case SLANT_OPT:
-	    if (slant)
-		usage_error(errh, "slant value specified twice");
-	    slant = clp->val.d;
-	    break;
-
-	  case LETTERSPACE_OPT:
-	    if (letterspace)
-		usage_error(errh, "letterspacing value specified twice");
-	    letterspace = clp->val.i;
-	    break;
-
-	  case SPACE_FACTOR_OPT:
-	    if (space_factor != 1)
-		usage_error(errh, "space factor specified twice");
-	    space_factor = clp->val.d;
-	    break;
-
-	  case MATH_SPACING_OPT:
-	    math_spacing = !clp->negated;
-	    if (math_spacing && clp->have_val) {
-		if (clp->val.i < 0 || clp->val.i > 255)
-		    usage_error(errh, "--math-spacing skew character must be between 0 and 255");
-		skew_char = clp->val.i;
-	    }
-	    break;
-
-	  case DESIGN_SIZE_OPT:
-	    if (design_size > 0)
-		usage_error(errh, "design size value specified twice");
-	    else if (clp->val.d <= 0)
-		usage_error(errh, "design size must be > 0");
-	    design_size = clp->val.d;
-	    break;
-
-	  case LIGKERN_OPT:
-	    ligkern.push_back(clp->vstr);
-	    break;
-
-	  case POSITION_OPT:
-	    pos.push_back(clp->vstr);
-	    break;
-
-	  case WARN_MISSING_OPT:
-	    warn_missing = !clp->negated;
-	    break;
-
-	  case NO_ECOMMAND_OPT:
-	    no_ecommand = true;
-	    break;
-
-	  case DEFAULT_LIGKERN_OPT:
-	    default_ligkern = !clp->negated;
-	    break;
-
-	  case BOUNDARY_CHAR_OPT:
-	    ligkern.push_back(String("|| = ") + String(clp->val.i));
-	    break;
-
-	  case ALTSELECTOR_CHAR_OPT:
-	    ligkern.push_back(String("^^ = ") + String(clp->val.i));
-	    break;
-
-	  case ALTSELECTOR_FEATURE_OPT: {
-	      OpenType::Tag t(clp->vstr);
-	      if (!t.valid())
-		  usage_error(errh, "bad feature tag");
-	      else if (altselector_feature_filters[t])
-		  usage_error(errh, "altselector feature %<%s%> included twice", t.text().c_str());
-	      else {
-		  if (!current_filter_ptr)
-		      current_filter_ptr = new GlyphFilter(current_substitution_filter + current_alternate_filter);
-		  altselector_features.push_back(t);
-		  altselector_feature_filters.insert(t, current_filter_ptr);
-	      }
-	      break;
-	  }
-
-	  case ALTERNATES_FILTER_OPT:
-	    current_alternate_filter = null_filter;
-	    /* fallthru */
-	  case EXCLUDE_ALTERNATES_OPT:
-	  case INCLUDE_ALTERNATES_OPT:
-	    current_alternate_filter.add_alternate_filter(clp->vstr, opt == EXCLUDE_ALTERNATES_OPT, errh);
-	    current_filter_ptr = 0;
-	    break;
-
-	  case CLEAR_ALTERNATES_OPT:
-	    current_alternate_filter = null_filter;
-	    current_filter_ptr = 0;
-	    break;
-
-	  case UNICODING_OPT:
-	    unicoding.push_back(clp->vstr);
-	    break;
-
-	  case CODINGSCHEME_OPT:
-	    if (codingscheme)
-		usage_error(errh, "coding scheme specified twice");
-	    codingscheme = clp->vstr;
-	    if (codingscheme.length() > 39)
-		errh->warning("only first 39 characters of coding scheme are significant");
-	    if (codingscheme.find_left('(') >= 0 || codingscheme.find_left(')') >= 0)
-		usage_error(errh, "coding scheme cannot contain parentheses");
-	    break;
-
-	  case AUTOMATIC_OPT:
-	    automatic = !clp->negated;
-	    break;
-
-	  case VENDOR_OPT:
-	    if (!set_vendor(clp->vstr))
-		usage_error(errh, "vendor name specified twice");
-	    break;
-
-	  case TYPEFACE_OPT:
-	    if (!set_typeface(clp->vstr, true))
-		usage_error(errh, "typeface name specified twice");
-	    break;
-
-	  case VIRTUAL_OPT:
-	    if (clp->negated)
-		output_flags &= ~G_VMETRICS;
-	    else
-		output_flags |= G_VMETRICS;
-	    break;
-
-	case NO_ENCODING_OPT:
-	case NO_TYPE1_OPT:
-	case NO_DOTLESSJ_OPT:
-	case NO_UPDMAP_OPT:
-	    output_flags &= ~(opt - NO_OUTPUT_OPTS);
-	    break;
-
-	case TRUETYPE_OPT:
-	case TYPE42_OPT:
-	    if (!clp->negated)
-		output_flags |= (opt - YES_OUTPUT_OPTS);
-	    else
-		output_flags &= ~(opt - YES_OUTPUT_OPTS);
-	    break;
-
-	  case OUTPUT_ENCODING_OPT:
-	    if (out_encoding_file)
-		usage_error(errh, "encoding output file specified twice");
-	    out_encoding_file = (clp->have_val ? clp->vstr : "-");
-	    output_flags = G_ENCODING;
-	    break;
-
-	  case MINIMUM_KERN_OPT:
-	    minimum_kern = clp->val.d;
-	    break;
-
-	  case MAP_FILE_OPT:
-	    if (clp->negated)
-		output_flags &= ~G_PSFONTSMAP;
-	    else {
-		output_flags |= G_PSFONTSMAP;
-		if (!set_map_file(clp->vstr))
-		    usage_error(errh, "map file specified twice");
-	    }
-	    break;
-
-	  case PL_OPT:
-	    output_flags = (output_flags & ~G_BINARY) | G_ASCII;
-	    break;
-
-	  case TFM_OPT:
-	    output_flags = (output_flags & ~G_ASCII) | G_BINARY;
-	    break;
-
-	case ENCODING_DIR_OPT:
-	case TFM_DIR_OPT:
-	case PL_DIR_OPT:
-	case VF_DIR_OPT:
-	case VPL_DIR_OPT:
-	case TYPE1_DIR_OPT:
-	case TRUETYPE_DIR_OPT:
-	case TYPE42_DIR_OPT:
-	    if (!setodir(opt - DIR_OPTS, clp->vstr))
-		usage_error(errh, "%s directory specified twice", odirname(opt - DIR_OPTS));
-	    break;
-
-	  case FONT_NAME_OPT:
-	  font_name:
-	    if (font_name)
-		usage_error(errh, "font name specified twice");
-	    font_name = clp->vstr;
-	    break;
-
-	case FIXED_PITCH_OPT:
-	    override_is_fixed_pitch = true;
-	    is_fixed_pitch = !clp->negated;
-	    break;
-
-	case PROPORTIONAL_WIDTH_OPT:
-	    override_is_fixed_pitch = true;
-	    is_fixed_pitch = !!clp->negated;
-	    break;
-
-	case ITALIC_ANGLE_OPT:
-	    override_italic_angle = true;
-	    italic_angle = clp->val.d;
-	    break;
-
-	  case GLYPHLIST_OPT:
-	    glyphlist_files.push_back(clp->vstr);
-	    break;
-
-	  case QUERY_FEATURES_OPT:
-	    usage_error(errh, "run %<otfinfo --query-features%> instead");
-	    break;
-
-	  case QUERY_SCRIPTS_OPT:
-	    usage_error(errh, "run %<otfinfo --query-scripts%> instead");
-	    break;
-
-	  case QUIET_OPT:
-	    if (clp->negated)
-		errh = ErrorHandler::default_handler();
-	    else
-		// 9.Nov.05 -- need a new SilentErrorHandler, because we use
-		// the base SilentErrorHandler elsewhere to ignore errors
-		errh = new SilentErrorHandler;
-	    break;
-
-	  case VERBOSE_OPT:
-	    verbose = !clp->negated;
-	    break;
-
-	  case NOCREATE_OPT:
-	    no_create = clp->negated;
-	    break;
-
-	  case FORCE_OPT:
-	    force = !clp->negated;
-	    break;
+          case OUTPUT_ENCODING_OPT:
+            if (out_encoding_file)
+                usage_error(errh, "encoding output file specified twice");
+            out_encoding_file = (clp->have_val ? clp->vstr : "-");
+            output_flags = G_ENCODING;
+            specified_output_flags = -1;
+            break;
+
+          case MINIMUM_KERN_OPT:
+            minimum_kern = clp->val.d;
+            break;
+
+          case MAP_FILE_OPT:
+            if (clp->negated)
+                output_flags &= ~G_PSFONTSMAP;
+            else {
+                output_flags |= G_PSFONTSMAP;
+                if (!set_map_file(clp->vstr))
+                    usage_error(errh, "map file specified twice");
+            }
+            specified_output_flags |= G_PSFONTSMAP;
+            break;
+
+        case PL_OPT:
+            if (clp->negated)
+                output_flags &= ~G_ASCII;
+            else
+                output_flags |= G_ASCII;
+            specified_output_flags |= G_ASCII;
+            break;
+
+        case TFM_OPT:
+            if (clp->negated)
+                output_flags &= ~G_BINARY;
+            else
+                output_flags |= G_BINARY;
+            specified_output_flags |= G_BINARY;
+            break;
+
+        case ENCODING_DIR_OPT:
+        case TFM_DIR_OPT:
+        case PL_DIR_OPT:
+        case VF_DIR_OPT:
+        case VPL_DIR_OPT:
+        case TYPE1_DIR_OPT:
+        case TRUETYPE_DIR_OPT:
+        case TYPE42_DIR_OPT:
+        case DIR_OPT:
+            if (!odirs[opt - DIR_OPTS])
+                odirs[opt - DIR_OPTS] = clp->vstr;
+            else
+                usage_error(errh, "%s directory specified twice", odirname(opt - DIR_OPTS));
+            break;
 
-	  case KPATHSEA_DEBUG_OPT:
+          case FONT_NAME_OPT:
+          font_name:
+            if (font_name)
+                usage_error(errh, "font name specified twice");
+            font_name = clp->vstr;
+            break;
+
+        case FIXED_PITCH_OPT:
+            override_is_fixed_pitch = true;
+            is_fixed_pitch = !clp->negated;
+            break;
+
+        case PROPORTIONAL_WIDTH_OPT:
+            override_is_fixed_pitch = true;
+            is_fixed_pitch = !!clp->negated;
+            break;
+
+        case ITALIC_ANGLE_OPT:
+            override_italic_angle = true;
+            italic_angle = clp->val.d;
+            break;
+
+          case GLYPHLIST_OPT:
+            glyphlist_files.push_back(clp->vstr);
+            break;
+
+          case QUERY_FEATURES_OPT:
+            usage_error(errh, "run %<otfinfo --query-features%> instead");
+            break;
+
+          case QUERY_SCRIPTS_OPT:
+            usage_error(errh, "run %<otfinfo --query-scripts%> instead");
+            break;
+
+          case QUIET_OPT:
+            if (clp->negated)
+                errh = ErrorHandler::default_handler();
+            else
+                // 9.Nov.05 -- need a new SilentErrorHandler, because we use
+                // the base SilentErrorHandler elsewhere to ignore errors
+                errh = new SilentErrorHandler;
+            break;
+
+          case VERBOSE_OPT:
+            verbose = !clp->negated;
+            break;
+
+          case NOCREATE_OPT:
+            no_create = clp->negated;
+            break;
+
+          case FORCE_OPT:
+            force = !clp->negated;
+            break;
+
+          case KPATHSEA_DEBUG_OPT:
 #if HAVE_KPATHSEA
-	    kpsei_set_debug_flags(clp->val.u);
+            kpsei_set_debug_flags(clp->val.u);
 #else
-	    errh->warning("Not compiled with kpathsea!");
+            errh->warning("Not compiled with kpathsea!");
 #endif
-	    break;
+            break;
 
         case X_HEIGHT_OPT: {
             char* ends;
@@ -2169,127 +2251,141 @@ main(int argc, char *argv[])
                      && *ends == 0 && *clp->vstr != 0)
                 override_x_height = FontInfo::x_height_explicit;
             else
-		usage_error(errh, "bad --x-height option");
+                usage_error(errh, "bad --x-height option");
             break;
         }
 
-	  case VERSION_OPT:
-	    printf("otftotfm (LCDF typetools) %s\n", VERSION);
-	    printf("Copyright (C) 2002-2016 Eddie Kohler\n\
+          case VERSION_OPT:
+            printf("otftotfm (LCDF typetools) %s\n", VERSION);
+            printf("Copyright (C) 2002-2018 Eddie Kohler\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;
+            exit(0);
+            break;
+
+          case HELP_OPT:
+            usage();
+            exit(0);
+            break;
+
+          case Clp_NotOption:
+            if (input_file && font_name)
+                usage_error(errh, "too many arguments");
+            else if (input_file)
+                goto font_name;
+            else
+                input_file = clp->vstr;
+            break;
+
+          case Clp_Done:
+            goto done;
 
-	  case HELP_OPT:
-	    usage();
-	    exit(0);
-	    break;
-
-	  case Clp_NotOption:
-	    if (input_file && font_name)
-		usage_error(errh, "too many arguments");
-	    else if (input_file)
-		goto font_name;
-	    else
-		input_file = clp->vstr;
-	    break;
-
-	  case Clp_Done:
-	    goto done;
-
-	  case Clp_BadOption:
-	    usage_error(errh, 0);
-	    break;
+          case Clp_BadOption:
+            usage_error(errh, 0);
+            break;
 
-	  default:
-	    break;
+          default:
+            break;
 
-	}
+        }
     }
 
   done:
     // check for odd option combinations
     if (warn_missing > 0 && !(output_flags & G_VMETRICS))
-	errh->warning("%<--warn-missing%> has no effect with %<--no-virtual%>");
+        errh->warning("%<--warn-missing%> has no effect with %<--no-virtual%>");
+    if (!(specified_output_flags & (G_BINARY | G_ASCII)))
+        output_flags |= G_BINARY;
 
     // set up file names
     if (!input_file)
-	usage_error(errh, "no font filename provided");
+        usage_error(errh, "no font filename provided");
     if (encoding_file == "-")
-	encoding_file = "";
+        encoding_file = "";
+
+    // set up output directories
+    if (odirs[NUMODIR]) {
+        for (int i = 0; i < NUMODIR; ++i)
+            if (!odirs[i])
+                odirs[i] = odirs[NUMODIR];
+    }
+    for (int i = 0; i < NUMODIR; ++i)
+        if (odirs[i])
+            setodir(i, odirs[i]);
 
     // set up feature filters
     if (!altselector_features.size()) {
-	if (!current_filter_ptr)
-	    current_filter_ptr = new GlyphFilter(current_substitution_filter + current_alternate_filter);
-	altselector_features.push_back(OpenType::Tag("dlig"));
-	altselector_feature_filters.insert(OpenType::Tag("dlig"), current_filter_ptr);
-	altselector_features.push_back(OpenType::Tag("salt"));
-	altselector_feature_filters.insert(OpenType::Tag("salt"), current_filter_ptr);
+        if (!current_filter_ptr) {
+            current_filter_ptr = new GlyphFilter(current_substitution_filter + current_alternate_filter);
+            allocated_filters.push_back(current_filter_ptr);
+        }
+        altselector_features.push_back(OpenType::Tag("dlig"));
+        altselector_feature_filters.insert(OpenType::Tag("dlig"), current_filter_ptr);
+        altselector_features.push_back(OpenType::Tag("salt"));
+        altselector_feature_filters.insert(OpenType::Tag("salt"), current_filter_ptr);
     } else if (!current_filter_ptr) {
-	errh->warning("some filtering options ignored");
-	errh->message("(--include-*, --exclude-*, and --*-filter options must occur\nbefore the feature options to which they should apply.)");
+        errh->warning("some filtering options ignored");
+        errh->message("(--include-*, --exclude-*, and --*-filter options must occur\nbefore the feature options to which they should apply.)");
     }
 
     try {
-	// read font
-	otf_data = read_file(input_file, errh);
-	if (errh->nerrors())
-	    exit(1);
-
-	LandmarkErrorHandler cerrh(errh, printable_filename(input_file));
-	BailErrorHandler bail_errh(&cerrh);
-
-	OpenType::Font otf(otf_data, &bail_errh);
-	assert(otf.ok());
-
-	// figure out scripts we care about
-	if (!interesting_scripts.size()) {
-	    interesting_scripts.push_back(Efont::OpenType::Tag("latn"));
-	    interesting_scripts.push_back(Efont::OpenType::Tag());
-	}
-	std::sort(interesting_features.begin(), interesting_features.end());
-	std::sort(altselector_features.begin(), altselector_features.end());
+        // read font
+        otf_data = read_file(input_file, errh);
+        if (errh->nerrors())
+            exit(1);
+
+        LandmarkErrorHandler cerrh(errh, printable_filename(input_file));
+        BailErrorHandler bail_errh(&cerrh);
+
+        OpenType::Font otf(otf_data, &bail_errh);
+        assert(otf.ok());
+
+        // figure out scripts we care about
+        if (!interesting_scripts.size()) {
+            interesting_scripts.push_back(Efont::OpenType::Tag("latn"));
+            interesting_scripts.push_back(Efont::OpenType::Tag());
+        }
+        std::sort(interesting_features.begin(), interesting_features.end());
+        std::sort(altselector_features.begin(), altselector_features.end());
 
-	// find glyphlist
-	if (!glyphlist_files.size()) {
+        // find glyphlist
+        if (!glyphlist_files.size()) {
 #if HAVE_KPATHSEA
-	    if (String g = kpsei_find_file("glyphlist.txt", KPSEI_FMT_MAP)) {
-		glyphlist_files.push_back(g);
-		if (verbose)
-		    errh->message("glyphlist.txt found with kpathsea at %s", g.c_str());
-	    } else
+            if (String g = kpsei_find_file("glyphlist.txt", KPSEI_FMT_MAP)) {
+                glyphlist_files.push_back(g);
+                if (verbose)
+                    errh->message("glyphlist.txt found with kpathsea at %s", g.c_str());
+            } else
 #endif
-		glyphlist_files.push_back(GLYPHLISTDIR "/glyphlist.txt");
+                glyphlist_files.push_back(GLYPHLISTDIR "/glyphlist.txt");
 #if HAVE_KPATHSEA
-	    if (String g = kpsei_find_file("texglyphlist.txt", KPSEI_FMT_MAP)) {
-		glyphlist_files.push_back(g);
-		if (verbose)
-		    errh->message("texglyphlist.txt found with kpathsea at %s", g.c_str());
-	    } else
+            if (String g = kpsei_find_file("texglyphlist.txt", KPSEI_FMT_MAP)) {
+                glyphlist_files.push_back(g);
+                if (verbose)
+                    errh->message("texglyphlist.txt found with kpathsea at %s", g.c_str());
+            } else
 #endif
-		glyphlist_files.push_back(GLYPHLISTDIR "/texglyphlist.txt");
-	}
+                glyphlist_files.push_back(GLYPHLISTDIR "/texglyphlist.txt");
+        }
 
-	// read glyphlist
-	for (String *g = glyphlist_files.begin(); g < glyphlist_files.end(); g++)
-	    if (String s = read_file(*g, errh, true))
-		DvipsEncoding::add_glyphlist(s);
-
-	// read base encodings
-	for (String *s = base_encoding_files.begin(); s < base_encoding_files.end(); s++)
-	    parse_base_encodings(*s, errh);
-
-	// read encoding
-	DvipsEncoding dvipsenc;
-	if (encoding_file) {
-	    if (String path = locate_encoding(encoding_file, errh))
-		dvipsenc.parse(path, no_ecommand, no_ecommand, errh);
-	    else
-		errh->fatal("encoding %<%s%> not found", encoding_file.c_str());
-	} else {
+        // read glyphlist
+        for (String *g = glyphlist_files.begin(); g < glyphlist_files.end(); g++)
+            if (String s = read_file(*g, errh, true))
+                DvipsEncoding::add_glyphlist(s);
+
+        // read base encodings
+        for (String *s = base_encoding_files.begin(); s < base_encoding_files.end(); s++)
+            parse_base_encodings(*s, errh);
+
+        // read encoding
+        DvipsEncoding dvipsenc;
+        if (encoding_file) {
+            if (String path = locate_encoding(encoding_file, errh))
+                dvipsenc.parse(path, no_ecommand, no_ecommand, errh);
+            else
+                errh->fatal("encoding %<%s%> not found", encoding_file.c_str());
+        } else {
             String cff_data(otf.table("CFF"));
             if (!cff_data) {
                 errh->error("explicit encoding required for TrueType fonts");
@@ -2300,42 +2396,44 @@ particular purpose.\n");
                 errh->message("(Use %<-e ENCODING%> to choose an encoding. %<-e texnansx%> often works,\nor say %<-e -%> to turn off this warning.)");
             }
 
-	    // use encoding from font
-	    Cff cff(cff_data, otf.units_per_em(), &bail_errh);
-	    Cff::FontParent *font = cff.font(PermString(), &bail_errh);
-	    assert(cff.ok() && font->ok());
-	    if (Type1Encoding *t1e = font->type1_encoding()) {
-		for (int i = 0; i < 256; i++)
-		    dvipsenc.encode(i, (*t1e)[i]);
-	    } else
-		errh->fatal("font has no encoding, specify one explicitly");
-	    delete font;
-	}
-
-	// apply default ligkern commands
-	if (default_ligkern)
-	    dvipsenc.parse_ligkern(default_ligkerns, 0, ErrorHandler::silent_handler());
-
-	// apply command-line ligkern commands and coding scheme
-	cerrh.set_landmark("--ligkern command");
-	for (int i = 0; i < ligkern.size(); i++)
-	    dvipsenc.parse_ligkern(ligkern[i], 1, &cerrh);
-	cerrh.set_landmark("--position command");
-	for (int i = 0; i < pos.size(); i++)
-	    dvipsenc.parse_position(pos[i], 1, &cerrh);
-	cerrh.set_landmark("--unicoding command");
-	for (int i = 0; i < unicoding.size(); i++)
-	    dvipsenc.parse_unicoding(unicoding[i], 1, &cerrh);
-	if (codingscheme)
-	    dvipsenc.set_coding_scheme(codingscheme);
-	if (warn_missing >= 0)
-	    dvipsenc.set_warn_missing(warn_missing);
+            // use encoding from font
+            Cff cff(cff_data, otf.units_per_em(), &bail_errh);
+            Cff::FontParent *font = cff.font(PermString(), &bail_errh);
+            assert(cff.ok() && font->ok());
+            if (Type1Encoding *t1e = font->type1_encoding()) {
+                for (int i = 0; i < 256; i++)
+                    dvipsenc.encode(i, (*t1e)[i]);
+            } else
+                errh->fatal("font has no encoding, specify one explicitly");
+        }
+
+        // apply default ligkern commands
+        if (default_ligkern)
+            dvipsenc.parse_ligkern(default_ligkerns, 0, ErrorHandler::silent_handler());
+
+        // apply command-line ligkern commands and coding scheme
+        cerrh.set_landmark("--ligkern command");
+        for (int i = 0; i < ligkern.size(); i++)
+            dvipsenc.parse_ligkern(ligkern[i], 1, &cerrh);
+        cerrh.set_landmark("--position command");
+        for (int i = 0; i < pos.size(); i++)
+            dvipsenc.parse_position(pos[i], 1, &cerrh);
+        cerrh.set_landmark("--unicoding command");
+        for (int i = 0; i < unicoding.size(); i++)
+            dvipsenc.parse_unicoding(unicoding[i], 1, &cerrh);
+        if (codingscheme)
+            dvipsenc.set_coding_scheme(codingscheme);
+        if (warn_missing >= 0)
+            dvipsenc.set_warn_missing(warn_missing);
 
-	do_file(input_file, otf, dvipsenc, literal_encoding, errh);
+        do_file(input_file, otf, dvipsenc, literal_encoding, errh);
 
     } catch (OpenType::Error e) {
-	errh->error("unhandled exception %<%s%>", e.description.c_str());
+        errh->error("unhandled exception %<%s%>", e.description.c_str());
     }
 
+    for (int i = 0; i < allocated_filters.size(); ++i)
+        delete allocated_filters[i];
+    Clp_DeleteParser(clp);
     return (errh->nerrors() == 0 ? 0 : 1);
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/otftotfm.hh	2018-02-23 12:47:54.094971678 -0500
@@ -11,11 +11,11 @@ String suffix_font_name(const String &fo
 String installed_metrics_font_name(const String &font_name, const String &secondary);
 
 void output_metrics(Metrics &metrics, const String &ps_name, int boundary_char,
-	const FontInfo &finfo,
-	const String &encoding_name, const String &encoding_file,
-	const String &font_name,
-	String (*dvips_include)(const String &ps_name, const FontInfo &, ErrorHandler *),
-	ErrorHandler *errh);
+        const FontInfo &finfo,
+        const String &encoding_name, const String &encoding_file,
+        const String &font_name,
+        String (*dvips_include)(const String &ps_name, const FontInfo &, ErrorHandler *),
+        ErrorHandler *errh);
 
 double font_cap_height(const FontInfo &, const Transform &);
 double font_ascender(const FontInfo &, const Transform &);
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.cc	2018-02-23 12:47:54.094971678 -0500
@@ -1,6 +1,6 @@
 /* secondary.{cc,hh} -- code for generating fake glyphs
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -33,45 +33,43 @@
 #include <algorithm>
 
 enum {
-    U_EXCLAMDOWN = 0x00A1,	// U+00A1 INVERTED EXCLAMATION MARK
-    U_DEGREE = 0x00B0,		// U+00B0 DEGREE SIGN
-    U_QUESTIONDOWN = 0x00BF,	// U+00BF INVERTED QUESTION MARK
-    U_IJ = 0x0132,		// U+0132 LATIN CAPITAL LIGATURE IJ
-    U_ij = 0x0133,		// U+0133 LATIN SMALL LIGATURE IJ
-    U_DOTLESSJ = 0x0237,	// U+0237 LATIN SMALL LETTER DOTLESS J
-    U_RINGABOVE = 0x02DA,	// U+02DA RING ABOVE
+    U_EXCLAMDOWN = 0x00A1,      // U+00A1 INVERTED EXCLAMATION MARK
+    U_DEGREE = 0x00B0,          // U+00B0 DEGREE SIGN
+    U_QUESTIONDOWN = 0x00BF,    // U+00BF INVERTED QUESTION MARK
+    U_IJ = 0x0132,              // U+0132 LATIN CAPITAL LIGATURE IJ
+    U_ij = 0x0133,              // U+0133 LATIN SMALL LIGATURE IJ
+    U_DOTLESSJ = 0x0237,        // U+0237 LATIN SMALL LETTER DOTLESS J
+    U_RINGABOVE = 0x02DA,       // U+02DA RING ABOVE
     U_COMBININGRINGABOVE = 0x030A, // U+030A COMBINING RING ABOVE
-    U_CWM = 0x200C,		// U+200C ZERO WIDTH NON-JOINER
-    U_ENDASH = 0x2013,		// U+2013 EN DASH
-    U_PERTENTHOUSAND = 0x2031,	// U+2031 PER TEN THOUSAND SIGN
-    U_INTERROBANG = 0x203D,	// U+203D INTERROBANG
-    U_FRACTION = 0x2044,	// U+2044 FRACTION SLASH
-    U_CENTIGRADE = 0x2103,	// U+2103 DEGREE CELSIUS
-    U_ASTERISKMATH = 0x2217,	// U+2217 ASTERISK OPERATOR
-    U_BARDBL = 0x2225,		// U+2225 PARALLEL TO
-    U_VISIBLESPACE = 0x2423,	// U+2423 OPEN BOX
-    U_DBLBRACKETLEFT = 0x27E6,	// U+27E6 MATHEMATICAL LEFT WHITE SQUARE BRACKET
-    U_DBLBRACKETRIGHT = 0x27E7,	// U+27E7 MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+    U_CWM = 0x200C,             // U+200C ZERO WIDTH NON-JOINER
+    U_ENDASH = 0x2013,          // U+2013 EN DASH
+    U_PERTENTHOUSAND = 0x2031,  // U+2031 PER TEN THOUSAND SIGN
+    U_INTERROBANG = 0x203D,     // U+203D INTERROBANG
+    U_FRACTION = 0x2044,        // U+2044 FRACTION SLASH
+    U_CENTIGRADE = 0x2103,      // U+2103 DEGREE CELSIUS
+    U_ASTERISKMATH = 0x2217,    // U+2217 ASTERISK OPERATOR
+    U_BARDBL = 0x2225,          // U+2225 PARALLEL TO
+    U_VISIBLESPACE = 0x2423,    // U+2423 OPEN BOX
+    U_DBLBRACKETLEFT = 0x27E6,  // U+27E6 MATHEMATICAL LEFT WHITE SQUARE BRACKET
+    U_DBLBRACKETRIGHT = 0x27E7, // U+27E7 MATHEMATICAL RIGHT WHITE SQUARE BRACKET
     U_INTERROBANGDOWN = 0x2E18, // U+2E18 INVERTED INTERROBANG
-    U_EMPTYSLOT = 0xD801,	// invalid Unicode (not handled by Secondary)
-    U_ALTSELECTOR = 0xD802,	// invalid Unicode
-    U_CAPITALCWM = 0xD809,	// invalid Unicode
-    U_ASCENDERCWM = 0xD80A,	// invalid Unicode
-    U_TWELVEUDASH = 0xD80C,	// invalid Unicode
-    U_RINGFITTED = 0xD80D,	// invalid Unicode
+    U_ALTSELECTOR = 0xD802,     // invalid Unicode
+    U_CAPITALCWM = 0xD809,      // invalid Unicode
+    U_ASCENDERCWM = 0xD80A,     // invalid Unicode
+    U_TWELVEUDASH = 0xD80C,     // invalid Unicode
+    U_RINGFITTED = 0xD80D,      // invalid Unicode
 
     // BEGIN BACKWARDS COMPATIBILITY -- newer texglyphlist.txt does not include
     // these code points
-    U_SS = 0xD800,		// invalid Unicode
-    U_SSSMALL = 0xD803,		// invalid Unicode
-    U_FFSMALL = 0xD804,		// invalid Unicode
-    U_FISMALL = 0xD805,		// invalid Unicode
-    U_FLSMALL = 0xD806,		// invalid Unicode
-    U_FFISMALL = 0xD807,	// invalid Unicode
-    U_FFLSMALL = 0xD808,	// invalid Unicode
+    U_SS = 0xD800,              // invalid Unicode
+    U_SSSMALL = 0xD803,         // invalid Unicode
+    U_FFSMALL = 0xD804,         // invalid Unicode
+    U_FISMALL = 0xD805,         // invalid Unicode
+    U_FLSMALL = 0xD806,         // invalid Unicode
+    U_FFISMALL = 0xD807,        // invalid Unicode
+    U_FFLSMALL = 0xD808,        // invalid Unicode
     // END BACKWARDS COMPATIBILITY
 
-    U_USE_KERNX = 0xD80E,	// invalid Unicode, not in maps
     U_VS1 = 0xFE00,
     U_VS16 = 0xFE0F,
     U_VS17 = 0xE0100,
@@ -82,7 +80,7 @@ enum {
     U_ISMALL = 0xF769,
     U_LSMALL = 0xF76C,
     U_SSMALL = 0xF773,
-    U_MATHDOTLESSJ = 0x1D6A5	// U+1D6A5 MATHEMATICAL ITALIC SMALL DOTLESS J
+    U_MATHDOTLESSJ = 0x1D6A5    // U+1D6A5 MATHEMATICAL ITALIC SMALL DOTLESS J
 };
 
 
@@ -95,27 +93,27 @@ FontInfo::FontInfo(const Efont::OpenType
     assert(cmap->ok());
 
     if (String cff_string = otf->table("CFF")) {
-	cff_file = new Efont::Cff(cff_string, otf->units_per_em(), errh);
-	if (!cff_file->ok())
-	    return;
-	Efont::Cff::FontParent *fp = cff_file->font(PermString(), errh);
-	if (!fp || !fp->ok())
-	    return;
-	if (!(cff = dynamic_cast<Efont::Cff::Font *>(fp))) {
-	    errh->error("CID-keyed fonts not supported");
-	    return;
-	}
-	_nglyphs = cff->nglyphs();
+        cff_file = new Efont::Cff(cff_string, otf->units_per_em(), errh);
+        if (!cff_file->ok())
+            return;
+        Efont::Cff::FontParent *fp = cff_file->font(PermString(), errh);
+        if (!fp || !fp->ok())
+            return;
+        if (!(cff = dynamic_cast<Efont::Cff::Font *>(fp))) {
+            errh->error("CID-keyed fonts not supported");
+            return;
+        }
+        _nglyphs = cff->nglyphs();
     }
 
     if (!cff) {
-	post = new Efont::OpenType::Post(otf->table("post"), errh);
-	// read number of glyphs from 'maxp' -- should probably be elsewhere
-	if (Efont::OpenType::Data maxp = otf->table("maxp"))
-	    if (maxp.length() >= 6)
-		_nglyphs = maxp.u16(4);
-	if (_nglyphs < 0 && post->ok())
-	    _nglyphs = post->nglyphs();
+        post = new Efont::OpenType::Post(otf->table("post"), errh);
+        // read number of glyphs from 'maxp' -- should probably be elsewhere
+        if (Efont::OpenType::Data maxp = otf->table("maxp"))
+            if (maxp.length() >= 6)
+                _nglyphs = maxp.u16(4);
+        if (_nglyphs < 0 && post->ok())
+            _nglyphs = post->nglyphs();
     }
 
     name = new Efont::OpenType::Name(otf->table("name"), errh);
@@ -125,7 +123,6 @@ FontInfo::~FontInfo()
 {
     delete cmap;
     delete cff_file;
-    delete cff;
     delete post;
     delete name;
     delete _ttb_program;
@@ -135,9 +132,9 @@ bool
 FontInfo::ok() const
 {
     if (cff)
-	return cmap->ok() && cff->ok();
+        return cmap->ok() && cff->ok();
     else
-	return post && post->ok() && name && name->ok();
+        return post && post->ok() && name && name->ok();
 }
 
 bool
@@ -151,16 +148,16 @@ int
 FontInfo::glyphid(PermString name) const
 {
     if (cff)
-	return cff->glyphid(name);
+        return cff->glyphid(name);
     else {
-	if (!_got_glyph_names) {
-	    glyph_names(_glyph_names);
-	    _got_glyph_names = true;
-	}
-	PermString *found = std::find(_glyph_names.begin(), _glyph_names.end(), name);
-	if (found == _glyph_names.end())
-	    return 0;
-	return found - _glyph_names.begin();
+        if (!_got_glyph_names) {
+            glyph_names(_glyph_names);
+            _got_glyph_names = true;
+        }
+        PermString *found = std::find(_glyph_names.begin(), _glyph_names.end(), name);
+        if (found == _glyph_names.end())
+            return 0;
+        return found - _glyph_names.begin();
     }
 }
 
@@ -168,29 +165,29 @@ String
 FontInfo::family_name() const
 {
     if (cff)
-	return cff->dict_string(Efont::Cff::oFamilyName);
+        return cff->dict_string(Efont::Cff::oFamilyName);
     else
-	return name->english_name(Efont::OpenType::Name::N_FAMILY);
+        return name->english_name(Efont::OpenType::Name::N_FAMILY);
 }
 
 String
 FontInfo::postscript_name() const
 {
     if (cff)
-	return cff->font_name();
+        return cff->font_name();
     else
-	return name->english_name(Efont::OpenType::Name::N_POSTSCRIPT);
+        return name->english_name(Efont::OpenType::Name::N_POSTSCRIPT);
 }
 
 const Efont::CharstringProgram *
 FontInfo::program() const
 {
     if (cff)
-	return cff;
+        return cff;
     else {
-	if (!_ttb_program)
-	    _ttb_program = new Efont::TrueTypeBoundsCharstringProgram(otf);
-	return _ttb_program;
+        if (!_ttb_program)
+            _ttb_program = new Efont::TrueTypeBoundsCharstringProgram(otf);
+        return _ttb_program;
     }
 }
 
@@ -198,25 +195,25 @@ bool
 FontInfo::is_fixed_pitch() const
 {
     if (_override_is_fixed_pitch)
-	return _is_fixed_pitch;
+        return _is_fixed_pitch;
     else if (cff) {
-	double d;
-	return (cff->dict_value(Efont::Cff::oIsFixedPitch, &d) && d);
+        double d;
+        return (cff->dict_value(Efont::Cff::oIsFixedPitch, &d) && d);
     } else
-	return post->is_fixed_pitch();
+        return post->is_fixed_pitch();
 }
 
 double
 FontInfo::italic_angle() const
 {
     if (_override_italic_angle)
-	return _italic_angle;
+        return _italic_angle;
     else if (cff) {
-	double d;
-	(void) cff->dict_value(Efont::Cff::oItalicAngle, &d);
-	return d;
+        double d;
+        (void) cff->dict_value(Efont::Cff::oItalicAngle, &d);
+        return d;
     } else
-	return post->italic_angle();
+        return post->italic_angle();
 }
 
 double FontInfo::x_height(const Transform& font_xform) const {
@@ -224,8 +221,8 @@ double FontInfo::x_height(const Transfor
         return _x_height;
     double x1 = -1, x2 = -1;
     if (_override_x_height != x_height_os2)
-	// XXX what if 'x', 'm', 'z' were subject to substitution?
-	x1 = char_one_bound(*this, font_xform, 3, false, units_per_em(),
+        // XXX what if 'x', 'm', 'z' were subject to substitution?
+        x1 = char_one_bound(*this, font_xform, 3, false, units_per_em(),
                             (int) 'x', (int) 'm', (int) 'z', 0);
     if (_override_x_height != x_height_x)
         try {
@@ -234,8 +231,10 @@ double FontInfo::x_height(const Transfor
         } catch (Efont::OpenType::Bounds) {
         }
     static bool warned = false;
-    if (_override_x_height == x_height_auto && x1 >= 0 && x2 >= 0
-        && fabs(x1 - x2) > units_per_em() / 100.) {
+    if (_override_x_height == x_height_auto
+        && x1 >= 0
+        && x2 >= 0
+        && fabs(x1 - x2) > units_per_em() / 50.) {
         if (!warned) {
             ErrorHandler* errh = ErrorHandler::default_handler();
             errh->warning("font x-height and height of %<x%> differ by %d%%", (int) (fabs(x1 - x2) * 100 / units_per_em()));
@@ -256,115 +255,82 @@ Secondary::~Secondary()
 
 bool
 Secondary::encode_uni(int code, PermString name,
-		      const uint32_t *uni_begin, const uint32_t *uni_end,
-		      Metrics &metrics, ErrorHandler *errh)
+                      const uint32_t* uni_begin, const uint32_t* uni_end,
+                      Metrics &metrics, ErrorHandler *errh)
 {
+    uint32_t uni = 0;
     if (uni_begin + 1 == uni_end)
-	return encode_uni(code, name, *uni_begin, metrics, errh);
-    else {
-	Vector<Setting> v;
-	int max_s = 0;
-	while (uni_begin != uni_end) {
-	    Vector<Setting> subv;
-	    int s = setting(*uni_begin, subv, metrics, errh);
-	    if (s == 0)
-		return false;
-	    if (subv.size() && v.size())
-		v.push_back(Setting(Setting::KERN));
-	    for (Vector<Setting>::const_iterator it = subv.begin();
-		 it != subv.end(); ++it)
-		v.push_back(*it);
-	    max_s = (max_s > s ? max_s : s);
-	    ++uni_begin;
-	}
-	metrics.encode_virtual(code, name, 0, v, max_s > 1);
-	return true;
+        uni = *uni_begin;
+
+    SettingSet set(this, metrics);
+    int max_s = 0;
+    while (uni_begin != uni_end) {
+        int s = setting(*uni_begin, set, errh);
+        if (s == 0)
+            return false;
+        max_s = (max_s > s ? max_s : s);
+        ++uni_begin;
+        set.checkpoint();
     }
-}
 
-bool
-Secondary::encode_uni(int code, PermString name, uint32_t uni, Metrics &metrics, ErrorHandler *errh)
-{
-    Vector<Setting> v;
-    if (int s = setting(uni, v, metrics, errh)) {
-	metrics.encode_virtual(code, name, uni, v, s > 1);
-	return true;
-    } else if (_next)
-	return _next->encode_uni(code, name, uni, metrics, errh);
-    else
-	return false;
+    if (uni == U_ALTSELECTOR
+        || (uni >= U_VS1 && uni <= U_VS16)
+        || (uni >= U_VS17 && uni <= U_VS256)) {
+        int selector = 0;
+        if (uni >= U_VS1 && uni <= U_VS16)
+            selector = uni - U_VS1 + 1;
+        else if (uni >= U_VS17 && uni <= U_VS256)
+            selector = uni - U_VS17 + 17;
+        metrics.add_altselector_code(code, selector);
+        name = selector ? permprintf("<vs%d>", selector) : PermString("<altselector>");
+    }
+
+    metrics.encode_virtual(code, name, 0, set.settings(), max_s > 1);
+    return true;
 }
 
 T1Secondary::T1Secondary(const FontInfo &finfo, const String &font_name,
-			 const String &otf_file_name)
-    : _finfo(finfo), _font_name(font_name), _otf_file_name(otf_file_name),
+                         const String &otf_file_name)
+    : Secondary(finfo), _font_name(font_name), _otf_file_name(otf_file_name),
       _units_per_em(finfo.units_per_em()),
       _xheight((int) ceil(finfo.x_height(Transform()))),
       _spacewidth(_units_per_em)
 {
     double bounds[4], width;
     if (char_bounds(bounds, width, finfo, Transform(), ' '))
-	_spacewidth = (int) ceil(width);
+        _spacewidth = (int) ceil(width);
 }
 
 int
-Secondary::setting(uint32_t uni, Vector<Setting> &v, Metrics &metrics, ErrorHandler *errh)
+Secondary::setting(uint32_t uni, SettingSet& set, ErrorHandler *errh)
 {
     if (_next)
-	return _next->setting(uni, v, metrics, errh);
+        return _next->setting(uni, set, errh);
     else
-	return 0;
+        return 0;
 }
 
-bool
-T1Secondary::char_setting(Vector<Setting> &v, Metrics &metrics, int uni, ...)
-{
-    Vector<int> codes;
-
-    // collect codes
-    va_list val;
-    va_start(val, uni);
-
-    int kerntype = Setting::KERN;
-    if (uni == U_USE_KERNX) {
-	kerntype = Setting::KERNX;
-	uni = va_arg(val, int);
-    }
-
-    for (; uni; uni = va_arg(val, int)) {
-	int code = metrics.unicode_encoding(uni);
-	if (code < 0) {
-	    Glyph glyph = _finfo.cmap->map_uni(uni);
-	    if (glyph == 0 || (code = metrics.force_encoding(glyph)) < 0)
-		return false;
-	}
-	codes.push_back(code);
-    }
-    va_end(val);
-
-    // generate setting
-    for (int i = 0; i < codes.size(); i++) {
-	if (i)
-	    v.push_back(Setting(kerntype));
-	v.push_back(Setting(Setting::SHOW, codes[i], metrics.base_glyph(codes[i])));
+SettingSet& SettingSet::show(int uni) {
+    if (!ok_)
+        return *this;
+    int code = metrics_.unicode_encoding(uni);
+    if (code < 0) {
+        Glyph glyph = s_->_finfo.cmap->map_uni(uni);
+        if (glyph != 0)
+            code = metrics_.force_encoding(glyph);
+    }
+    if (code < 0) {
+        ok_ = false;
+        while (v_.size() > original_size_)
+            v_.pop_back();
+    } else {
+        if (!v_.empty()
+            && v_.back().op == Setting::SHOW
+            && kern_type_)
+            v_.push_back(Setting(kern_type_));
+        v_.push_back(Setting(Setting::SHOW, code, metrics_.base_glyph(code)));
     }
-    return true;
-}
-
-bool
-T1Secondary::encode_uni(int code, PermString name, uint32_t uni, Metrics &metrics, ErrorHandler *errh)
-{
-    if (uni == U_ALTSELECTOR
-	|| (uni >= U_VS1 && uni <= U_VS16)
-	|| (uni >= U_VS17 && uni <= U_VS256)) {
-	Vector<Setting> v;
-	setting(uni, v, metrics, errh);
-	int which = (uni == U_ALTSELECTOR ? 0 : (uni <= U_VS16 ? uni - U_VS1 + 1 : uni - U_VS17 + 17));
-	metrics.encode_virtual(code, (which ? permprintf("<vs%d>", which) : PermString("<altselector>")), uni, v, false);
-	metrics.add_altselector_code(code, which);
-	return true;
-    } else
-	return Secondary::encode_uni(code, name, uni, metrics, errh);
+    return *this;
 }
 
 
@@ -380,355 +346,333 @@ int
 T1Secondary::dotlessj_font(Metrics &metrics, ErrorHandler *errh, Glyph &dj_glyph)
 {
     if (!_font_name || !_finfo.otf || !_finfo.cff)
-	return -1;
+        return -1;
 
     String dj_name;
     bool install_metrics;
     // XXX make sure dotlessj is for the main font?
     if ((dj_name = installed_metrics_font_name(_font_name, "dotlessj")))
-	install_metrics = false;
+        install_metrics = false;
     else {
-	dj_name = suffix_font_name(_font_name, "--lcdfj");
-	install_metrics = true;
+        dj_name = suffix_font_name(_font_name, "--lcdfj");
+        install_metrics = true;
     }
 
     // is dotlessj already mapped?
     for (int i = 0; i < metrics.n_mapped_fonts(); i++)
-	if (metrics.mapped_font_name(i) == dj_name)
-	    return i;
+        if (metrics.mapped_font_name(i) == dj_name)
+            return i;
 
     if (String filename = installed_type1_dotlessj(_otf_file_name, _finfo.cff->font_name(), (output_flags & G_DOTLESSJ), errh)) {
 
-	// check for special case: "\0" means the font's "j" is already
-	// dotless
-	if (filename == String("\0", 1))
-	    return J_NODOT;
-
-	// open dotless-j font file
-	FILE *f = fopen(filename.c_str(), "rb");
-	if (!f) {
-	    errh->error("%s: %s", filename.c_str(), strerror(errno));
-	    return -1;
-	}
-
-	// read font
-	Efont::Type1Reader *reader;
-	int c = getc(f);
-	ungetc(c, f);
-	if (c == 128)
-	    reader = new Efont::Type1PFBReader(f);
-	else
-	    reader = new Efont::Type1PFAReader(f);
-	Efont::Type1Font *font = new Efont::Type1Font(*reader);
-	delete reader;
-
-	if (!font->ok()) {
-	    errh->error("%s: no glyphs in dotless-J font", filename.c_str());
-	    delete font;
-	    return -1;
-	}
-
-	// find dotless-J character
-	Vector<PermString> glyph_names;
-	font->glyph_names(glyph_names);
-	Vector<PermString>::iterator g = std::find(glyph_names.begin(), glyph_names.end(), "uni0237");
-	if (g == glyph_names.end()) {
-	    errh->error("%s: dotless-J font has no %<uni0237%> glyph", filename.c_str());
-	    delete font;
-	    return -1;
-	}
-	dj_glyph = g - glyph_names.begin();
-
-	// create metrics for dotless-J
-	if (install_metrics) {
-	    Metrics dj_metrics(font, 256);
-	    dj_metrics.encode('j', U_DOTLESSJ, dj_glyph);
-	    ::dotlessj_file_name = filename;
-	    output_metrics(dj_metrics, font->font_name(), -1, _finfo, String(), String(), dj_name, dotlessj_dvips_include, errh);
-	} else if (verbose)
-	    errh->message("using %<%s%> for dotless-J font metrics", dj_name.c_str());
+        // check for special case: "\0" means the font's "j" is already
+        // dotless
+        if (filename == String("\0", 1))
+            return J_NODOT;
+
+        // open dotless-j font file
+        FILE *f = fopen(filename.c_str(), "rb");
+        if (!f) {
+            errh->error("%s: %s", filename.c_str(), strerror(errno));
+            return -1;
+        }
 
-	// add font to metrics
-	return metrics.add_mapped_font(font, dj_name);
+        // read font
+        Efont::Type1Reader *reader;
+        int c = getc(f);
+        ungetc(c, f);
+        if (c == 128)
+            reader = new Efont::Type1PFBReader(f);
+        else
+            reader = new Efont::Type1PFAReader(f);
+        Efont::Type1Font *font = new Efont::Type1Font(*reader);
+        delete reader;
+
+        if (!font->ok()) {
+            errh->error("%s: no glyphs in dotless-J font", filename.c_str());
+            delete font;
+            return -1;
+        }
+
+        // find dotless-J character
+        Vector<PermString> glyph_names;
+        font->glyph_names(glyph_names);
+        Vector<PermString>::iterator g = std::find(glyph_names.begin(), glyph_names.end(), "uni0237");
+        if (g == glyph_names.end()) {
+            errh->error("%s: dotless-J font has no %<uni0237%> glyph", filename.c_str());
+            delete font;
+            return -1;
+        }
+        dj_glyph = g - glyph_names.begin();
+
+        // create metrics for dotless-J
+        if (install_metrics) {
+            Metrics dj_metrics(font, 256);
+            dj_metrics.encode('j', U_DOTLESSJ, dj_glyph);
+            ::dotlessj_file_name = filename;
+            output_metrics(dj_metrics, font->font_name(), -1, _finfo, String(), String(), dj_name, dotlessj_dvips_include, errh);
+        } else if (verbose)
+            errh->message("using %<%s%> for dotless-J font metrics", dj_name.c_str());
+
+        // add font to metrics
+        return metrics.add_mapped_font(font, dj_name);
 
     } else
-	return -1;
+        return -1;
 }
 
 int
-T1Secondary::setting(uint32_t uni, Vector<Setting> &v, Metrics &metrics, ErrorHandler *errh)
+T1Secondary::setting(uint32_t uni, SettingSet& set, ErrorHandler *errh)
 {
     Transform xform;
-    int vsize = v.size();
     extern int letterspace;
 
-    if (char_setting(v, metrics, uni, 0))
-	return 1;
+    if (set.show(uni).check())
+        return 1;
 
     switch (uni) {
 
       case U_CWM:
       case U_ALTSELECTOR:
-	v.push_back(Setting(Setting::RULE, 0, _xheight));
-	return 1;
+        set.push_back(Setting::RULE, 0, _xheight);
+        return 1;
 
       case U_CAPITALCWM:
-	v.push_back(Setting(Setting::RULE, 0, font_cap_height(_finfo, xform)));
-	return 1;
+        set.push_back(Setting::RULE, 0, font_cap_height(_finfo, xform));
+        return 1;
 
       case U_ASCENDERCWM:
-	v.push_back(Setting(Setting::RULE, 0, font_ascender(_finfo, xform)));
-	return 1;
+        set.push_back(Setting::RULE, 0, font_ascender(_finfo, xform));
+        return 1;
 
     case U_VISIBLESPACE: {
         int sb = (int) (0.050 * _units_per_em), h = (int) (0.150 * _units_per_em),
             lw = (int) (0.040 * _units_per_em);
-	v.push_back(Setting(Setting::MOVE, sb, -h));
-	v.push_back(Setting(Setting::RULE, lw, h));
-	v.push_back(Setting(Setting::RULE, _spacewidth, lw));
-	v.push_back(Setting(Setting::RULE, lw, h));
-	v.push_back(Setting(Setting::MOVE, sb, h));
-	return 2;
-    }
-
-      case U_SS:
-	if (char_setting(v, metrics, 'S', 'S', 0))
-	    return 1;
-	break;
-
-      case U_SSSMALL:
-	if (char_setting(v, metrics, U_SSMALL, U_SSMALL, 0))
-	    return 1;
-	else if (char_setting(v, metrics, 's', 's', 0))
-	    return 1;
-	break;
+        set.move(sb, -h);
+        set.push_back(Setting::RULE, lw, h);
+        set.push_back(Setting::RULE, _spacewidth, lw);
+        set.push_back(Setting::RULE, lw, h);
+        set.move(sb, h);
+        return 2;
+    }
+
+    case U_SS:
+        if (set.show('S').show('S').check())
+            return 1;
+        break;
+
+    case U_SSSMALL:
+        if (set.show(U_SSMALL).show(U_SSMALL).check()
+            || set.show('s').show('s').check())
+            return 1;
+        break;
 
       case U_FFSMALL:
-	if (char_setting(v, metrics, U_FSMALL, U_FSMALL, 0))
-	    return 1;
-	else if (char_setting(v, metrics, 'f', 'f', 0))
-	    return 1;
-	break;
+        if (set.show(U_FSMALL).show(U_FSMALL).check()
+            || set.show('f').show('f').check())
+            return 1;
+        break;
 
       case U_FISMALL:
-	if (char_setting(v, metrics, U_FSMALL, U_ISMALL, 0))
-	    return 1;
-	else if (char_setting(v, metrics, 'f', 'i', 0))
-	    return 1;
-	break;
+        if (set.show(U_FSMALL).show(U_ISMALL).check()
+            || set.show('f').show('i').check())
+            return 1;
+        break;
 
       case U_FLSMALL:
-	if (char_setting(v, metrics, U_FSMALL, U_LSMALL, 0))
-	    return 1;
-	else if (char_setting(v, metrics, 'f', 'l', 0))
-	    return 1;
-	break;
+        if (set.show(U_FSMALL).show(U_LSMALL).check()
+            || set.show('f').show('l').check())
+            return 1;
+        break;
 
       case U_FFISMALL:
-	if (char_setting(v, metrics, U_FSMALL, U_FSMALL, U_ISMALL, 0))
-	    return 1;
-	else if (char_setting(v, metrics, 'f', 'f', 'i', 0))
-	    return 1;
-	break;
+        if (set.show(U_FSMALL).show(U_FSMALL).show(U_ISMALL).check()
+            || set.show('f').show('f').show('i').check())
+            return 1;
+        break;
 
       case U_FFLSMALL:
-	if (char_setting(v, metrics, U_FSMALL, U_FSMALL, U_LSMALL, 0))
-	    return 1;
-	else if (char_setting(v, metrics, 'f', 'f', 'l', 0))
-	    return 1;
-	break;
+        if (set.show(U_FSMALL).show(U_FSMALL).show(U_LSMALL).check()
+            || set.show('f').show('f').show('l').check())
+            return 1;
+        break;
 
       case U_IJ:
-	if (char_setting(v, metrics, 'I', 'J', 0))
-	    return 1;
-	break;
+        if (set.show('I').show('J').check())
+            return 1;
+        break;
 
       case U_ij:
-	if (char_setting(v, metrics, 'i', 'j', 0))
-	    return 1;
-	break;
+        if (set.show('i').show('j').check())
+            return 1;
+        break;
 
       case U_DOTLESSJ:
       case U_DOTLESSJ_2:
       case U_MATHDOTLESSJ: {
-	  Glyph dj_glyph;
-	  int which = dotlessj_font(metrics, errh, dj_glyph);
-	  if (which >= 0) {
-	      v.push_back(Setting(Setting::FONT, which));
-	      v.push_back(Setting(Setting::SHOW, 'j', dj_glyph));
-	      return 2;
-	  } else if (which == J_NODOT && char_setting(v, metrics, 'j', 0))
-	      return 1;
-	  break;
+          Glyph dj_glyph;
+          int which = dotlessj_font(set.metrics(), errh, dj_glyph);
+          if (which >= 0) {
+              set.push_back(Setting::FONT, which);
+              set.push_back(Setting::SHOW, 'j', dj_glyph);
+              return 2;
+          } else if (which == J_NODOT && set.show('j').check())
+              return 1;
+          break;
       }
 
       case U_DBLBRACKETLEFT:
-	if (char_setting(v, metrics, '[', 0)) {
-	    if (!_finfo.is_fixed_pitch()) {
-		double d = char_one_bound(_finfo, xform, 4, true, 0, '[', 0);
-		v.push_back(Setting(Setting::MOVE, (int) (-0.666 * d - letterspace), 0));
-	    }
-	    char_setting(v, metrics, '[', 0);
-	    return 1;
-	}
-	break;
+        if (set.show('[').check()) {
+            if (!_finfo.is_fixed_pitch()) {
+                double d = char_one_bound(_finfo, xform, 4, true, 0, '[', 0);
+                set.move((int) (-0.666 * d - letterspace));
+            }
+            set.show('[');
+            return 1;
+        }
+        break;
 
       case U_DBLBRACKETRIGHT:
-	if (char_setting(v, metrics, ']', 0)) {
-	    if (!_finfo.is_fixed_pitch()) {
-		double d = char_one_bound(_finfo, xform, 4, true, 0, ']', 0);
-		v.push_back(Setting(Setting::MOVE, (int) (-0.666 * d - letterspace), 0));
-	    }
-	    char_setting(v, metrics, ']', 0);
-	    return 1;
-	}
-	break;
+        if (set.show(']').check()) {
+            if (!_finfo.is_fixed_pitch()) {
+                double d = char_one_bound(_finfo, xform, 4, true, 0, ']', 0);
+                set.move((int) (-0.666 * d - letterspace));
+            }
+            set.show(']');
+            return 1;
+        }
+        break;
 
       case U_BARDBL:
-	if (char_setting(v, metrics, '|', 0)) {
-	    if (!_finfo.is_fixed_pitch()) {
-		double d = char_one_bound(_finfo, Transform(), 4, true, 0, '|', 0);
-		v.push_back(Setting(Setting::MOVE, (int) (-0.333 * d - letterspace), 0));
-	    }
-	    char_setting(v, metrics, '|', 0);
-	    return 1;
-	}
-	break;
+        if (set.show('|').check()) {
+            if (!_finfo.is_fixed_pitch()) {
+                double d = char_one_bound(_finfo, Transform(), 4, true, 0, '|', 0);
+                set.move((int) (-0.333 * d - letterspace));
+            }
+            set.show('|');
+            return 1;
+        }
+        break;
 
       case U_ASTERISKMATH: {
-	  double bounds[5];
-	  double dropdown = 0;
-	  if (char_bounds(bounds, bounds[4], _finfo, xform, '*'))
-	      dropdown += std::max(bounds[3], 0.) + std::min(bounds[1], 0.);
-	  if (char_bounds(bounds, bounds[4], _finfo, xform, '('))
-	      dropdown -= std::max(bounds[3], 0.) + std::min(bounds[1], 0.);
-	  v.push_back(Setting(Setting::MOVE, 0, (int) (-dropdown / 2)));
-	  if (char_setting(v, metrics, '*', 0)) {
-	      v.push_back(Setting(Setting::MOVE, 0, -(int) (-dropdown / 2)));
-	      return 1;
-	  }
-	  break;
+          double bounds[5];
+          double dropdown = 0;
+          if (char_bounds(bounds, bounds[4], _finfo, xform, '*'))
+              dropdown += std::max(bounds[3], 0.) + std::min(bounds[1], 0.);
+          if (char_bounds(bounds, bounds[4], _finfo, xform, '('))
+              dropdown -= std::max(bounds[3], 0.) + std::min(bounds[1], 0.);
+          int dy = (int) (-dropdown / 2);
+          if (set.move(0, dy).show('*').move(0, -dy).check())
+              return 1;
+          break;
       }
 
       case U_TWELVEUDASH:
-	if (char_setting(v, metrics, U_ENDASH, 0)) {
-	    if (!_finfo.is_fixed_pitch()) {
-		double d = char_one_bound(_finfo, xform, 4, true, 0, U_ENDASH, 0);
-		v.push_back(Setting(Setting::MOVE, (int) (_units_per_em * 0.667 - 2 * d - letterspace), 0));
-	    }
-	    char_setting(v, metrics, U_ENDASH, 0);
-	    return 1;
-	}
-	break;
+        if (set.show(U_ENDASH).check()) {
+            if (!_finfo.is_fixed_pitch()) {
+                double d = char_one_bound(_finfo, xform, 4, true, 0, U_ENDASH, 0);
+                set.move((int) (_units_per_em * 0.667 - 2 * d - letterspace));
+            }
+            set.show(U_ENDASH);
+            return 1;
+        }
+        break;
 
       case U_THREEQUARTERSEMDASH:
-	if (char_setting(v, metrics, U_ENDASH, 0)) {
-	    if (!_finfo.is_fixed_pitch()) {
-		double d = char_one_bound(_finfo, xform, 4, true, 0, U_ENDASH, 0);
-		v.push_back(Setting(Setting::MOVE, (int) (_units_per_em * 0.750 - 2 * d - letterspace), 0));
-	    }
-	    char_setting(v, metrics, U_ENDASH, 0);
-	    return 1;
-	}
-	break;
+        if (set.show(U_ENDASH).check()) {
+            if (!_finfo.is_fixed_pitch()) {
+                double d = char_one_bound(_finfo, xform, 4, true, 0, U_ENDASH, 0);
+                set.move((int) (_units_per_em * 0.750 - 2 * d - letterspace));
+            }
+            set.show(U_ENDASH);
+            return 1;
+        }
+        break;
 
       case U_CENTIGRADE:
         // TODO: set italic correction to that of a 'C'
-	if (char_setting(v, metrics, U_USE_KERNX, U_DEGREE, 'C', 0))
-	    return 1;
-	break;
+        if (set.show(U_DEGREE).kernx(true).show('C').kernx(false).check())
+            return 1;
+        break;
 
       case U_INTERROBANG: {
-	  double exclam_offset =
-	      (char_one_bound(_finfo, xform, 4, true, 0, '?', 0)
-	       - char_one_bound(_finfo, xform, 4, true, 0, '!', 0)) * 0.5
+          double exclam_offset =
+              (char_one_bound(_finfo, xform, 4, true, 0, '?', 0)
+               - char_one_bound(_finfo, xform, 4, true, 0, '!', 0)) * 0.5
               + 0.050 * _units_per_em;
-	  v.push_back(Setting(Setting::PUSH));
-	  v.push_back(Setting(Setting::MOVE, (int) exclam_offset, 0));
-	  if (char_setting(v, metrics, '!', 0)) {
-	      v.push_back(Setting(Setting::POP));
-	      if (char_setting(v, metrics, '?', 0))
-		  return 1;
-	  }
-	  break;
+          if (set.push_back(Setting::PUSH).move((int) exclam_offset)
+              .show('!').push_back(Setting::POP).show('?').check())
+              return 1;
+          break;
       }
 
       case U_INTERROBANGDOWN: {
-	  double exclam_offset =
-	      (char_one_bound(_finfo, xform, 4, true, 0, U_QUESTIONDOWN, 0)
-	       - char_one_bound(_finfo, xform, 4, true, 0, U_EXCLAMDOWN, 0)) * 0.5
+          double exclam_offset =
+              (char_one_bound(_finfo, xform, 4, true, 0, U_QUESTIONDOWN, 0)
+               - char_one_bound(_finfo, xform, 4, true, 0, U_EXCLAMDOWN, 0)) * 0.5
               + 0.050 * _units_per_em;
-	  v.push_back(Setting(Setting::PUSH));
-	  v.push_back(Setting(Setting::MOVE, (int) exclam_offset, 0));
-	  if (char_setting(v, metrics, U_EXCLAMDOWN, 0)) {
-	      v.push_back(Setting(Setting::POP));
-	      if (char_setting(v, metrics, U_QUESTIONDOWN, 0))
-		  return 1;
-	  }
-	  break;
+          if (set.push_back(Setting::PUSH).move((int) exclam_offset)
+              .show(U_EXCLAMDOWN).push_back(Setting::POP).show(U_QUESTIONDOWN).check())
+              return 1;
+          break;
       }
 
       case U_PERTENTHOUSAND:
-	if (char_setting(v, metrics, U_USE_KERNX, 0xF661, U_FRACTION, 0xF655, 0xF655, 0xF655, 0))
-	    return 1;
-	break;
+        if (set.show(0xF661).kernx(true).show(U_FRACTION)
+            .show(0xF655).show(0xF655).show(0xF655).kernx(false).check())
+            return 1;
+        break;
 
       case U_RINGFITTED: {
-	  int A_width = char_one_bound(_finfo, xform, 4, true, -_units_per_em, 'A', 0);
-	  uint32_t ring_char = U_RINGABOVE;
-	  int ring_width = char_one_bound(_finfo, xform, 4, true, -_units_per_em, ring_char, 0);
-	  if (ring_width <= -_units_per_em) {
-	      ring_char = U_COMBININGRINGABOVE;
-	      ring_width = char_one_bound(_finfo, xform, 4, true, -_units_per_em, ring_char, 0);
-	  }
-	  if (A_width > -_units_per_em && ring_width > -_units_per_em) {
-	      int offset = (A_width - ring_width) / 2;
-	      v.push_back(Setting(Setting::MOVE, offset, 0));
-	      if (char_setting(v, metrics, ring_char, 0)) {
-		  v.push_back(Setting(Setting::MOVE, A_width - ring_width - offset, 0));
-		  return 1;
-	      }
-	  }
-	  break;
+          int A_width = char_one_bound(_finfo, xform, 4, true, -_units_per_em, 'A', 0);
+          uint32_t ring_char = U_RINGABOVE;
+          int ring_width = char_one_bound(_finfo, xform, 4, true, -_units_per_em, ring_char, 0);
+          if (ring_width <= -_units_per_em) {
+              ring_char = U_COMBININGRINGABOVE;
+              ring_width = char_one_bound(_finfo, xform, 4, true, -_units_per_em, ring_char, 0);
+          }
+          if (A_width > -_units_per_em && ring_width > -_units_per_em) {
+              int offset = (A_width - ring_width) / 2;
+              if (set.move(offset).show(ring_char).move(A_width - ring_width - offset).check()) {
+                  return 1;
+              }
+          }
+          break;
       }
 
     }
 
-    // didn't find a good setting, restore v to pristine state
-    while (v.size() > vsize)
-	v.pop_back();
-
     // variant selectors get the same setting as ALTSELECTOR
     if ((uni >= U_VS1 && uni <= U_VS16) || (uni >= U_VS17 && uni <= U_VS256))
-	return setting(U_ALTSELECTOR, v, metrics, errh);
+        return setting(U_ALTSELECTOR, set, errh);
 
     // otherwise, try other secondaries
-    return Secondary::setting(uni, v, metrics, errh);
+    return Secondary::setting(uni, set, errh);
 }
 
 
 bool
 char_bounds(double bounds[4], double& width, const FontInfo &finfo,
-	    const Transform &transform, uint32_t uni)
+            const Transform &transform, uint32_t uni)
 {
     if (Efont::OpenType::Glyph g = finfo.cmap->map_uni(uni))
-	return Efont::CharstringBounds::bounds(transform, finfo.program()->glyph_context(g), bounds, width);
+        return Efont::CharstringBounds::bounds(transform, finfo.program()->glyph_context(g), bounds, width);
     else
-	return false;
+        return false;
 }
 
 double
 char_one_bound(const FontInfo &finfo, const Transform &transform,
-	       int dimen, bool max, double best, int uni, ...)
+               int dimen, bool max, double best, int uni, ...)
 {
     double bounds[5];
     va_list val;
     va_start(val, uni);
     while (uni != 0) {
-	if (char_bounds(bounds, bounds[4], finfo, transform, uni))
-	    if (max ? bounds[dimen] > best : bounds[dimen] < best)
-		best = bounds[dimen];
-	uni = va_arg(val, int);
+        if (char_bounds(bounds, bounds[4], finfo, transform, uni))
+            if (max ? bounds[dimen] > best : bounds[dimen] < best)
+                best = bounds[dimen];
+        uni = va_arg(val, int);
     }
     va_end(val);
     return best;
@@ -738,12 +682,12 @@ double
 font_cap_height(const FontInfo &finfo, const Transform &font_xform)
 {
     try {
-	Efont::OpenType::Os2 os2(finfo.otf->table("OS/2"));
-	return os2.cap_height();
+        Efont::OpenType::Os2 os2(finfo.otf->table("OS/2"));
+        return os2.cap_height();
     } catch (Efont::OpenType::Bounds) {
-	// XXX what if 'H', 'O', 'B' were subject to substitution?
-	return char_one_bound(finfo, font_xform, 3, false, finfo.units_per_em(),
-			      (int) 'H', (int) 'O', (int) 'B', 0);
+        // XXX what if 'H', 'O', 'B' were subject to substitution?
+        return char_one_bound(finfo, font_xform, 3, false, finfo.units_per_em(),
+                              (int) 'H', (int) 'O', (int) 'B', 0);
     }
 }
 
@@ -751,12 +695,12 @@ double
 font_ascender(const FontInfo &finfo, const Transform &font_xform)
 {
     try {
-	Efont::OpenType::Os2 os2(finfo.otf->table("OS/2"));
-	return os2.typo_ascender();
+        Efont::OpenType::Os2 os2(finfo.otf->table("OS/2"));
+        return os2.typo_ascender();
     } catch (Efont::OpenType::Bounds) {
-	// XXX what if 'd', 'l' were subject to substitution?
-	return char_one_bound(finfo, font_xform, 3, true,
-			      finfo.x_height(font_xform),
-			      (int) 'd', (int) 'l', 0);
+        // XXX what if 'd', 'l' were subject to substitution?
+        return char_one_bound(finfo, font_xform, 3, true,
+                              finfo.x_height(font_xform),
+                              (int) 'd', (int) 'l', 0);
     }
 }
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/secondary.hh	2018-02-23 12:47:54.094971678 -0500
@@ -2,9 +2,10 @@
 #define OTFTOTFM_SECONDARY_HH
 #include <efont/otfcmap.hh>
 #include <efont/cff.hh>
+#include "setting.hh"
 class Metrics;
+class Secondary;
 class Transform;
-struct Setting;
 namespace Efont { class TrueTypeBoundsCharstringProgram; }
 
 struct FontInfo {
@@ -23,12 +24,12 @@ struct FontInfo {
 
     bool ok() const;
 
-    int nglyphs() const			{ return _nglyphs; }
+    int nglyphs() const                 { return _nglyphs; }
     bool glyph_names(Vector<PermString> &) const;
     int glyphid(PermString) const;
     const Efont::CharstringProgram *program() const;
     int units_per_em() const {
-	return program()->units_per_em();
+        return program()->units_per_em();
     }
 
     bool is_fixed_pitch() const;
@@ -36,12 +37,12 @@ struct FontInfo {
     double x_height(const Transform& font_xform) const;
 
     void set_is_fixed_pitch(bool is_fixed_pitch) {
-	_override_is_fixed_pitch = true;
-	_is_fixed_pitch = is_fixed_pitch;
+        _override_is_fixed_pitch = true;
+        _is_fixed_pitch = is_fixed_pitch;
     }
     void set_italic_angle(double italic_angle) {
-	_override_italic_angle = true;
-	_italic_angle = italic_angle;
+        _override_italic_angle = true;
+        _italic_angle = italic_angle;
     }
     enum { x_height_auto = 0, x_height_explicit,
            x_height_os2, x_height_x };
@@ -69,38 +70,108 @@ struct FontInfo {
 
 };
 
+class SettingSet {
+public:
+    inline SettingSet(Secondary* s, Metrics& m);
+    inline SettingSet& push_back(Setting s);
+    inline SettingSet& push_back(int op, int x = 0, int y = 0);
+    inline SettingSet& move(int x, int y = 0);
+    SettingSet& show(int uni);
+    inline SettingSet& kernx(bool is_kernx);
+    inline bool check();
+    inline void checkpoint();
+    inline Metrics& metrics() const;
+    inline const Vector<Setting>& settings() const;
+private:
+    Secondary* s_;
+    Vector<Setting> v_;
+    int original_size_;
+    Metrics& metrics_;
+    int kern_type_;
+    bool ok_;
+    typedef Efont::OpenType::Glyph Glyph;
+};
+
 class Secondary { public:
-    Secondary()				: _next(0) { }
+    Secondary(const FontInfo& finfo)    : _finfo(finfo), _next(0) { }
     virtual ~Secondary();
-    void set_next(Secondary *s)		{ _next = s; }
+    void set_next(Secondary *s)         { _next = s; }
     typedef Efont::OpenType::Glyph Glyph;
-    bool encode_uni(int code, PermString name, const uint32_t *uni_begin, const uint32_t *uni_end, Metrics &metrics, ErrorHandler *errh);
-    virtual bool encode_uni(int code, PermString name, uint32_t uni, Metrics &, ErrorHandler *);
-    virtual int setting(uint32_t uni, Vector<Setting> &, Metrics &, ErrorHandler *);
+    bool encode_uni(int code, PermString name, const uint32_t* uni_first, const uint32_t* uni_last, Metrics &metrics, ErrorHandler *errh);
+    inline bool encode_uni(int code, PermString name, uint32_t uni, Metrics& m, ErrorHandler* errh);
+    virtual int setting(uint32_t uni, SettingSet&, ErrorHandler *);
+  protected:
+    const FontInfo& _finfo;
+
+    friend class SettingSet;
   private:
     Secondary *_next;
 };
 
 class T1Secondary : public Secondary { public:
     T1Secondary(const FontInfo &, const String &font_name, const String &otf_file_name);
-    bool encode_uni(int code, PermString name, uint32_t uni, Metrics &, ErrorHandler *);
-    int setting(uint32_t uni, Vector<Setting> &, Metrics &, ErrorHandler *);
+    int setting(uint32_t uni, SettingSet&, ErrorHandler *);
   private:
-    const FontInfo &_finfo;
     String _font_name;
     String _otf_file_name;
     int _units_per_em;
     int _xheight;
     int _spacewidth;
-    bool char_setting(Vector<Setting> &, Metrics &, int uni, ...);
     enum { J_NODOT = -1031892 /* unlikely value */ };
     int dotlessj_font(Metrics &, ErrorHandler *, Glyph &dj_glyph);
 };
 
 bool char_bounds(double bounds[4], double& width, const FontInfo &,
-		 const Transform &, uint32_t uni);
+                 const Transform &, uint32_t uni);
 
 double char_one_bound(const FontInfo &, const Transform &,
                       int dimen, bool max, double best, int uni, ...);
 
+inline SettingSet::SettingSet(Secondary* s, Metrics& m)
+    : s_(s), original_size_(0), metrics_(m),
+      kern_type_(Setting::KERN), ok_(true) {
+}
+
+inline SettingSet& SettingSet::kernx(bool is_kernx) {
+    kern_type_ = is_kernx ? Setting::KERNX : Setting::KERN;
+    return *this;
+}
+
+inline SettingSet& SettingSet::push_back(Setting s) {
+    if (ok_)
+        v_.push_back(s);
+    return *this;
+}
+
+inline SettingSet& SettingSet::push_back(int op, int x, int y) {
+    return push_back(Setting(op, x, y));
+}
+
+inline SettingSet& SettingSet::move(int x, int y) {
+    return push_back(Setting(Setting::MOVE, x, y));
+}
+
+inline bool SettingSet::check() {
+    bool ok = ok_;
+    ok_ = true;
+    return ok;
+}
+
+inline void SettingSet::checkpoint() {
+    assert(ok_);
+    original_size_ = v_.size();
+}
+
+inline Metrics& SettingSet::metrics() const {
+    return metrics_;
+}
+
+inline const Vector<Setting>& SettingSet::settings() const {
+    return v_;
+}
+
+inline bool Secondary::encode_uni(int code, PermString name, uint32_t uni, Metrics& m, ErrorHandler* errh) {
+    return encode_uni(code, name, &uni, &uni + 1, m, errh);
+}
+
 #endif
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/setting.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/setting.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/setting.hh.git4166ff9	2018-02-23 12:59:25.406658041 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/setting.hh	2018-02-23 12:59:10.984019250 -0500
@@ -0,0 +1,18 @@
+#ifndef OTFTOTFM_SETTING_HH
+#define OTFTOTFM_SETTING_HH
+#include <lcdf/string.hh>
+
+struct Setting {
+    enum { NONE, FONT, SHOW, KERN, KERNX, MOVE, RULE, PUSH, POP,
+           SPECIAL, DEAD };
+    int op;
+    int x;
+    int y;
+    String s;
+    Setting(int op_in, int x_in = 0, int y_in = 0)
+        : op(op_in), x(x_in), y(y_in) { }
+    Setting(int op_in, const String &s_in) : op(op_in), s(s_in) { }
+    bool valid_op() const               { return op >= FONT && op <= SPECIAL; }
+};
+
+#endif
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.cc	2018-02-23 12:47:54.095971653 -0500
@@ -1,6 +1,6 @@
 /* uniprop.{cc,hh} -- code for Unicode character properties
  *
- * Copyright (c) 2004-2016 Eddie Kohler
+ * Copyright (c) 2004-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -25,12 +25,12 @@ const unsigned char UnicodeProperty::pro
     0, P_Lul, 48, P_Cn, 49, P_Lu, 87, P_Cn, 89, P_Lm, 90, P_Po, 96, P_Cn, 97, P_Ll, 136, P_Cn, 137, P_Po, 138, P_Pd, 139, P_Cn, 141, P_So, 143, P_Sc, 144, P_Cn, 145, P_Mn, 190, P_Pd, 191, P_Mn, 192, P_Po, 193, P_Mn, 195, P_Po, 196, P_Mn, 198, P_Po, 199, P_Mn, 200, P_Cn, 208, P_Lo, 235, P_Cn, 240, P_Lo, 243, P_Po, 245, P_Cn,
     0, P_Cf, 6, P_Sm, 9, P_Po, 11, P_Sc, 12, P_Po, 14, P_So, 16, P_Mn, 27, P_Po, 28, P_Cf, 29, P_Cn, 30, P_Po, 32, P_Lo, 64, P_Lm, 65, P_Lo, 75, P_Mn, 96, P_Nd, 106, P_Po, 110, P_Lo, 112, P_Mn, 113, P_Lo, 212, P_Po, 213, P_Lo, 214, P_Mn, 221, P_Cf, 222, P_So, 223, P_Mn, 229, P_Lm, 231, P_Mn, 233, P_So, 234, P_Mn, 238, P_Lo, 240, P_Nd, 250, P_Lo, 253, P_So, 255, P_Lo,
     0, P_Po, 14, P_Cn, 15, P_Cf, 16, P_Lo, 17, P_Mn, 18, P_Lo, 48, P_Mn, 75, P_Cn, 77, P_Lo, 166, P_Mn, 177, P_Lo, 178, P_Cn, 192, P_Nd, 202, P_Lo, 235, P_Mn, 244, P_Lm, 246, P_So, 247, P_Po, 250, P_Lm, 251, P_Cn,
-    0, P_Lo, 22, P_Mn, 26, P_Lm, 27, P_Mn, 36, P_Lm, 37, P_Mn, 40, P_Lm, 41, P_Mn, 46, P_Cn, 48, P_Po, 63, P_Cn, 64, P_Lo, 89, P_Mn, 92, P_Cn, 94, P_Po, 95, P_Cn, 160, P_Lo, 181, P_Cn, 227, P_Mn,
+    0, P_Lo, 22, P_Mn, 26, P_Lm, 27, P_Mn, 36, P_Lm, 37, P_Mn, 40, P_Lm, 41, P_Mn, 46, P_Cn, 48, P_Po, 63, P_Cn, 64, P_Lo, 89, P_Mn, 92, P_Cn, 94, P_Po, 95, P_Cn, 160, P_Lo, 181, P_Cn, 182, P_Lo, 190, P_Cn, 212, P_Mn, 226, P_Cf, 227, P_Mn,
     0, P_Mn, 3, P_Mc, 4, P_Lo, 58, P_Mn, 59, P_Mc, 60, P_Mn, 61, P_Lo, 62, P_Mc, 65, P_Mn, 73, P_Mc, 77, P_Mn, 78, P_Mc, 80, P_Lo, 81, P_Mn, 88, P_Lo, 98, P_Mn, 100, P_Po, 102, P_Nd, 112, P_Po, 113, P_Lm, 114, P_Lo, 129, P_Mn, 130, P_Mc, 132, P_Cn, 133, P_Lo, 141, P_Cn, 143, P_Lo, 145, P_Cn, 147, P_Lo, 169, P_Cn, 170, P_Lo, 177, P_Cn, 178, P_Lo, 179, P_Cn, 182, P_Lo, 186, P_Cn, 188, P_Mn, 189, P_Lo, 190, P_Mc, 193, P_Mn, 197, P_Cn, 199, P_Mc, 201, P_Cn, 203, P_Mc, 205, P_Mn, 206, P_Lo, 207, P_Cn, 215, P_Mc, 216, P_Cn, 220, P_Lo, 222, P_Cn, 223, P_Lo, 226, P_Mn, 228, P_Cn, 230, P_Nd, 240, P_Lo, 242, P_Sc, 244, P_No, 250, P_So, 251, P_Sc, 252, P_Cn,
     0, P_Cn, 1, P_Mn, 3, P_Mc, 4, P_Cn, 5, P_Lo, 11, P_Cn, 15, P_Lo, 17, P_Cn, 19, P_Lo, 41, P_Cn, 42, P_Lo, 49, P_Cn, 50, P_Lo, 52, P_Cn, 53, P_Lo, 55, P_Cn, 56, P_Lo, 58, P_Cn, 60, P_Mn, 61, P_Cn, 62, P_Mc, 65, P_Mn, 67, P_Cn, 71, P_Mn, 73, P_Cn, 75, P_Mn, 78, P_Cn, 81, P_Mn, 82, P_Cn, 89, P_Lo, 93, P_Cn, 94, P_Lo, 95, P_Cn, 102, P_Nd, 112, P_Mn, 114, P_Lo, 117, P_Mn, 118, P_Cn, 129, P_Mn, 131, P_Mc, 132, P_Cn, 133, P_Lo, 142, P_Cn, 143, P_Lo, 146, P_Cn, 147, P_Lo, 169, P_Cn, 170, P_Lo, 177, P_Cn, 178, P_Lo, 180, P_Cn, 181, P_Lo, 186, P_Cn, 188, P_Mn, 189, P_Lo, 190, P_Mc, 193, P_Mn, 198, P_Cn, 199, P_Mn, 201, P_Mc, 202, P_Cn, 203, P_Mc, 205, P_Mn, 206, P_Cn, 208, P_Lo, 209, P_Cn, 224, P_Lo, 226, P_Mn, 228, P_Cn, 230, P_Nd, 240, P_Po, 241, P_Sc, 242, P_Cn, 249, P_Lo, 250, P_Cn,
     0, P_Cn, 1, P_Mn, 2, P_Mc, 4, P_Cn, 5, P_Lo, 13, P_Cn, 15, P_Lo, 17, P_Cn, 19, P_Lo, 41, P_Cn, 42, P_Lo, 49, P_Cn, 50, P_Lo, 52, P_Cn, 53, P_Lo, 58, P_Cn, 60, P_Mn, 61, P_Lo, 62, P_Mc, 63, P_Mn, 64, P_Mc, 65, P_Mn, 69, P_Cn, 71, P_Mc, 73, P_Cn, 75, P_Mc, 77, P_Mn, 78, P_Cn, 86, P_Mn, 87, P_Mc, 88, P_Cn, 92, P_Lo, 94, P_Cn, 95, P_Lo, 98, P_Mn, 100, P_Cn, 102, P_Nd, 112, P_So, 113, P_Lo, 114, P_No, 120, P_Cn, 130, P_Mn, 131, P_Lo, 132, P_Cn, 133, P_Lo, 139, P_Cn, 142, P_Lo, 145, P_Cn, 146, P_Lo, 150, P_Cn, 153, P_Lo, 155, P_Cn, 156, P_Lo, 157, P_Cn, 158, P_Lo, 160, P_Cn, 163, P_Lo, 165, P_Cn, 168, P_Lo, 171, P_Cn, 174, P_Lo, 186, P_Cn, 190, P_Mc, 192, P_Mn, 193, P_Mc, 195, P_Cn, 198, P_Mc, 201, P_Cn, 202, P_Mc, 205, P_Mn, 206, P_Cn, 208, P_Lo, 209, P_Cn, 215, P_Mc, 216, P_Cn, 230, P_Nd, 240, P_No, 243, P_So, 249, P_Sc, 250, P_So, 251, P_Cn,
-    0, P_Mn, 1, P_Mc, 4, P_Cn, 5, P_Lo, 13, P_Cn, 14, P_Lo, 17, P_Cn, 18, P_Lo, 41, P_Cn, 42, P_Lo, 58, P_Cn, 61, P_Lo, 62, P_Mn, 65, P_Mc, 69, P_Cn, 70, P_Mn, 73, P_Cn, 74, P_Mn, 78, P_Cn, 85, P_Mn, 87, P_Cn, 88, P_Lo, 91, P_Cn, 96, P_Lo, 98, P_Mn, 100, P_Cn, 102, P_Nd, 112, P_Cn, 120, P_No, 127, P_So, 128, P_Cn, 129, P_Mn, 130, P_Mc, 132, P_Cn, 133, P_Lo, 141, P_Cn, 142, P_Lo, 145, P_Cn, 146, P_Lo, 169, P_Cn, 170, P_Lo, 180, P_Cn, 181, P_Lo, 186, P_Cn, 188, P_Mn, 189, P_Lo, 190, P_Mc, 191, P_Mn, 192, P_Mc, 197, P_Cn, 198, P_Mn, 199, P_Mc, 201, P_Cn, 202, P_Mc, 204, P_Mn, 206, P_Cn, 213, P_Mc, 215, P_Cn, 222, P_Lo, 223, P_Cn, 224, P_Lo, 226, P_Mn, 228, P_Cn, 230, P_Nd, 240, P_Cn, 241, P_Lo, 243, P_Cn,
-    0, P_Cn, 1, P_Mn, 2, P_Mc, 4, P_Cn, 5, P_Lo, 13, P_Cn, 14, P_Lo, 17, P_Cn, 18, P_Lo, 59, P_Cn, 61, P_Lo, 62, P_Mc, 65, P_Mn, 69, P_Cn, 70, P_Mc, 73, P_Cn, 74, P_Mc, 77, P_Mn, 78, P_Lo, 79, P_Cn, 87, P_Mc, 88, P_Cn, 95, P_Lo, 98, P_Mn, 100, P_Cn, 102, P_Nd, 112, P_No, 118, P_Cn, 121, P_So, 122, P_Lo, 128, P_Cn, 130, P_Mc, 132, P_Cn, 133, P_Lo, 151, P_Cn, 154, P_Lo, 178, P_Cn, 179, P_Lo, 188, P_Cn, 189, P_Lo, 190, P_Cn, 192, P_Lo, 199, P_Cn, 202, P_Mn, 203, P_Cn, 207, P_Mc, 210, P_Mn, 213, P_Cn, 214, P_Mn, 215, P_Cn, 216, P_Mc, 224, P_Cn, 230, P_Nd, 240, P_Cn, 242, P_Mc, 244, P_Po, 245, P_Cn,
+    0, P_Mn, 1, P_Mc, 4, P_Cn, 5, P_Lo, 13, P_Cn, 14, P_Lo, 17, P_Cn, 18, P_Lo, 41, P_Cn, 42, P_Lo, 58, P_Cn, 61, P_Lo, 62, P_Mn, 65, P_Mc, 69, P_Cn, 70, P_Mn, 73, P_Cn, 74, P_Mn, 78, P_Cn, 85, P_Mn, 87, P_Cn, 88, P_Lo, 91, P_Cn, 96, P_Lo, 98, P_Mn, 100, P_Cn, 102, P_Nd, 112, P_Cn, 120, P_No, 127, P_So, 128, P_Lo, 129, P_Mn, 130, P_Mc, 132, P_Cn, 133, P_Lo, 141, P_Cn, 142, P_Lo, 145, P_Cn, 146, P_Lo, 169, P_Cn, 170, P_Lo, 180, P_Cn, 181, P_Lo, 186, P_Cn, 188, P_Mn, 189, P_Lo, 190, P_Mc, 191, P_Mn, 192, P_Mc, 197, P_Cn, 198, P_Mn, 199, P_Mc, 201, P_Cn, 202, P_Mc, 204, P_Mn, 206, P_Cn, 213, P_Mc, 215, P_Cn, 222, P_Lo, 223, P_Cn, 224, P_Lo, 226, P_Mn, 228, P_Cn, 230, P_Nd, 240, P_Cn, 241, P_Lo, 243, P_Cn,
+    0, P_Cn, 1, P_Mn, 2, P_Mc, 4, P_Cn, 5, P_Lo, 13, P_Cn, 14, P_Lo, 17, P_Cn, 18, P_Lo, 59, P_Cn, 61, P_Lo, 62, P_Mc, 65, P_Mn, 69, P_Cn, 70, P_Mc, 73, P_Cn, 74, P_Mc, 77, P_Mn, 78, P_Lo, 79, P_So, 80, P_Cn, 84, P_Lo, 87, P_Mc, 88, P_No, 95, P_Lo, 98, P_Mn, 100, P_Cn, 102, P_Nd, 112, P_No, 121, P_So, 122, P_Lo, 128, P_Cn, 130, P_Mc, 132, P_Cn, 133, P_Lo, 151, P_Cn, 154, P_Lo, 178, P_Cn, 179, P_Lo, 188, P_Cn, 189, P_Lo, 190, P_Cn, 192, P_Lo, 199, P_Cn, 202, P_Mn, 203, P_Cn, 207, P_Mc, 210, P_Mn, 213, P_Cn, 214, P_Mn, 215, P_Cn, 216, P_Mc, 224, P_Cn, 230, P_Nd, 240, P_Cn, 242, P_Mc, 244, P_Po, 245, P_Cn,
     0, P_Cn, 1, P_Lo, 49, P_Mn, 50, P_Lo, 52, P_Mn, 59, P_Cn, 63, P_Sc, 64, P_Lo, 70, P_Lm, 71, P_Mn, 79, P_Po, 80, P_Nd, 90, P_Po, 92, P_Cn, 129, P_Lo, 131, P_Cn, 132, P_Lo, 133, P_Cn, 135, P_Lo, 137, P_Cn, 138, P_Lo, 139, P_Cn, 141, P_Lo, 142, P_Cn, 148, P_Lo, 152, P_Cn, 153, P_Lo, 160, P_Cn, 161, P_Lo, 164, P_Cn, 165, P_Lo, 166, P_Cn, 167, P_Lo, 168, P_Cn, 170, P_Lo, 172, P_Cn, 173, P_Lo, 177, P_Mn, 178, P_Lo, 180, P_Mn, 186, P_Cn, 187, P_Mn, 189, P_Lo, 190, P_Cn, 192, P_Lo, 197, P_Cn, 198, P_Lm, 199, P_Cn, 200, P_Mn, 206, P_Cn, 208, P_Nd, 218, P_Cn, 220, P_Lo, 224, P_Cn,
     0, P_Lo, 1, P_So, 4, P_Po, 19, P_So, 20, P_Po, 21, P_So, 24, P_Mn, 26, P_So, 32, P_Nd, 42, P_No, 52, P_So, 53, P_Mn, 54, P_So, 55, P_Mn, 56, P_So, 57, P_Mn, 58, P_Ps, 59, P_Pe, 60, P_Ps, 61, P_Pe, 62, P_Mc, 64, P_Lo, 72, P_Cn, 73, P_Lo, 109, P_Cn, 113, P_Mn, 127, P_Mc, 128, P_Mn, 133, P_Po, 134, P_Mn, 136, P_Lo, 141, P_Mn, 152, P_Cn, 153, P_Mn, 189, P_Cn, 190, P_So, 198, P_Mn, 199, P_So, 205, P_Cn, 206, P_So, 208, P_Po, 213, P_So, 217, P_Po, 219, P_Cn,
     0, P_Lo, 43, P_Mc, 45, P_Mn, 49, P_Mc, 50, P_Mn, 56, P_Mc, 57, P_Mn, 59, P_Mc, 61, P_Mn, 63, P_Lo, 64, P_Nd, 74, P_Po, 80, P_Lo, 86, P_Mc, 88, P_Mn, 90, P_Lo, 94, P_Mn, 97, P_Lo, 98, P_Mc, 101, P_Lo, 103, P_Mc, 110, P_Lo, 113, P_Mn, 117, P_Lo, 130, P_Mn, 131, P_Mc, 133, P_Mn, 135, P_Mc, 141, P_Mn, 142, P_Lo, 143, P_Mc, 144, P_Nd, 154, P_Mc, 157, P_Mn, 158, P_So, 160, P_Lu, 198, P_Cn, 199, P_Lu, 200, P_Cn, 205, P_Lu, 206, P_Cn, 208, P_Lo, 251, P_Po, 252, P_Lm, 253, P_Lo,
@@ -40,18 +40,18 @@ const unsigned char UnicodeProperty::pro
     0, P_Pd, 1, P_Lo,
     0, P_Lo, 109, P_Po, 111, P_Lo, 128, P_Zs, 129, P_Lo, 155, P_Ps, 156, P_Pe, 157, P_Cn, 160, P_Lo, 235, P_Po, 238, P_Nl, 241, P_Lo, 249, P_Cn,
     0, P_Lo, 13, P_Cn, 14, P_Lo, 18, P_Mn, 21, P_Cn, 32, P_Lo, 50, P_Mn, 53, P_Po, 55, P_Cn, 64, P_Lo, 82, P_Mn, 84, P_Cn, 96, P_Lo, 109, P_Cn, 110, P_Lo, 113, P_Cn, 114, P_Mn, 116, P_Cn, 128, P_Lo, 180, P_Mn, 182, P_Mc, 183, P_Mn, 190, P_Mc, 198, P_Mn, 199, P_Mc, 201, P_Mn, 212, P_Po, 215, P_Lm, 216, P_Po, 219, P_Sc, 220, P_Lo, 221, P_Mn, 222, P_Cn, 224, P_Nd, 234, P_Cn, 240, P_No, 250, P_Cn,
-    0, P_Po, 6, P_Pd, 7, P_Po, 11, P_Mn, 14, P_Cf, 15, P_Cn, 16, P_Nd, 26, P_Cn, 32, P_Lo, 67, P_Lm, 68, P_Lo, 120, P_Cn, 128, P_Lo, 169, P_Mn, 170, P_Lo, 171, P_Cn, 176, P_Lo, 246, P_Cn,
+    0, P_Po, 6, P_Pd, 7, P_Po, 11, P_Mn, 14, P_Cf, 15, P_Cn, 16, P_Nd, 26, P_Cn, 32, P_Lo, 67, P_Lm, 68, P_Lo, 120, P_Cn, 128, P_Lo, 133, P_Mn, 135, P_Lo, 169, P_Mn, 170, P_Lo, 171, P_Cn, 176, P_Lo, 246, P_Cn,
     0, P_Lo, 31, P_Cn, 32, P_Mn, 35, P_Mc, 39, P_Mn, 41, P_Mc, 44, P_Cn, 48, P_Mc, 50, P_Mn, 51, P_Mc, 57, P_Mn, 60, P_Cn, 64, P_So, 65, P_Cn, 68, P_Po, 70, P_Nd, 80, P_Lo, 110, P_Cn, 112, P_Lo, 117, P_Cn, 128, P_Lo, 172, P_Cn, 176, P_Lo, 202, P_Cn, 208, P_Nd, 218, P_No, 219, P_Cn, 222, P_So,
     0, P_Lo, 23, P_Mn, 25, P_Mc, 27, P_Mn, 28, P_Cn, 30, P_Po, 32, P_Lo, 85, P_Mc, 86, P_Mn, 87, P_Mc, 88, P_Mn, 95, P_Cn, 96, P_Mn, 97, P_Mc, 98, P_Mn, 99, P_Mc, 101, P_Mn, 109, P_Mc, 115, P_Mn, 125, P_Cn, 127, P_Mn, 128, P_Nd, 138, P_Cn, 144, P_Nd, 154, P_Cn, 160, P_Po, 167, P_Lm, 168, P_Po, 174, P_Cn, 176, P_Mn, 190, P_Me, 191, P_Cn,
     0, P_Mn, 4, P_Mc, 5, P_Lo, 52, P_Mn, 53, P_Mc, 54, P_Mn, 59, P_Mc, 60, P_Mn, 61, P_Mc, 66, P_Mn, 67, P_Mc, 69, P_Lo, 76, P_Cn, 80, P_Nd, 90, P_Po, 97, P_So, 107, P_Mn, 116, P_So, 125, P_Cn, 128, P_Mn, 130, P_Mc, 131, P_Lo, 161, P_Mc, 162, P_Mn, 166, P_Mc, 168, P_Mn, 170, P_Mc, 171, P_Mn, 174, P_Lo, 176, P_Nd, 186, P_Lo, 230, P_Mn, 231, P_Mc, 232, P_Mn, 234, P_Mc, 237, P_Mn, 238, P_Mc, 239, P_Mn, 242, P_Mc, 244, P_Cn, 252, P_Po,
-    0, P_Lo, 36, P_Mc, 44, P_Mn, 52, P_Mc, 54, P_Mn, 56, P_Cn, 59, P_Po, 64, P_Nd, 74, P_Cn, 77, P_Lo, 80, P_Nd, 90, P_Lo, 120, P_Lm, 126, P_Po, 128, P_Cn, 192, P_Po, 200, P_Cn, 208, P_Mn, 211, P_Po, 212, P_Mn, 225, P_Mc, 226, P_Mn, 233, P_Lo, 237, P_Mn, 238, P_Lo, 242, P_Mc, 244, P_Mn, 245, P_Lo, 247, P_Cn, 248, P_Mn, 250, P_Cn,
-    0, P_Ll, 44, P_Lm, 107, P_Ll, 120, P_Lm, 121, P_Ll, 155, P_Lm, 192, P_Mn, 246, P_Cn, 252, P_Mn,
+    0, P_Lo, 36, P_Mc, 44, P_Mn, 52, P_Mc, 54, P_Mn, 56, P_Cn, 59, P_Po, 64, P_Nd, 74, P_Cn, 77, P_Lo, 80, P_Nd, 90, P_Lo, 120, P_Lm, 126, P_Po, 128, P_Ll, 137, P_Cn, 192, P_Po, 200, P_Cn, 208, P_Mn, 211, P_Po, 212, P_Mn, 225, P_Mc, 226, P_Mn, 233, P_Lo, 237, P_Mn, 238, P_Lo, 242, P_Mc, 244, P_Mn, 245, P_Lo, 247, P_Cn, 248, P_Mn, 250, P_Cn,
+    0, P_Ll, 44, P_Lm, 107, P_Ll, 120, P_Lm, 121, P_Ll, 155, P_Lm, 192, P_Mn, 246, P_Cn, 251, P_Mn,
     0, P_Lul, 150, P_Ll, 158, P_Lul,
     0, P_Ll, 8, P_Lu, 16, P_Ll, 22, P_Cn, 24, P_Lu, 30, P_Cn, 32, P_Ll, 40, P_Lu, 48, P_Ll, 56, P_Lu, 64, P_Ll, 70, P_Cn, 72, P_Lu, 78, P_Cn, 80, P_Ll, 88, P_Cn, 89, P_Lu, 90, P_Cn, 91, P_Lu, 92, P_Cn, 93, P_Lu, 94, P_Cn, 95, P_Lul, 97, P_Ll, 104, P_Lu, 112, P_Ll, 126, P_Cn, 128, P_Ll, 136, P_Lt, 144, P_Ll, 152, P_Lt, 160, P_Ll, 168, P_Lt, 176, P_Ll, 181, P_Cn, 182, P_Ll, 184, P_Lu, 188, P_Lt, 189, P_Sk, 190, P_Ll, 191, P_Sk, 194, P_Ll, 197, P_Cn, 198, P_Ll, 200, P_Lu, 204, P_Lt, 205, P_Sk, 208, P_Ll, 212, P_Cn, 214, P_Ll, 216, P_Lu, 220, P_Cn, 221, P_Sk, 224, P_Ll, 232, P_Lu, 237, P_Sk, 240, P_Cn, 242, P_Ll, 245, P_Cn, 246, P_Ll, 248, P_Lu, 252, P_Lt, 253, P_Sk, 255, P_Cn,
     0, P_Zs, 11, P_Cf, 16, P_Pd, 22, P_Po, 24, P_Pi, 25, P_Pf, 26, P_Ps, 27, P_Pi, 29, P_Pf, 30, P_Ps, 31, P_Pi, 32, P_Po, 40, P_Zl, 41, P_Zp, 42, P_Cf, 47, P_Zs, 48, P_Po, 57, P_Pi, 58, P_Pf, 59, P_Po, 63, P_Pc, 65, P_Po, 68, P_Sm, 69, P_Ps, 70, P_Pe, 71, P_Po, 82, P_Sm, 83, P_Po, 84, P_Pc, 85, P_Po, 95, P_Zs, 96, P_Cf, 101, P_Cn, 102, P_Cf, 112, P_No, 113, P_Lm, 114, P_Cn, 116, P_No, 122, P_Sm, 125, P_Ps, 126, P_Pe, 127, P_Lm, 128, P_No, 138, P_Sm, 141, P_Ps, 142, P_Pe, 143, P_Cn, 144, P_Lm, 157, P_Cn, 160, P_Sc, 191, P_Cn, 208, P_Mn, 221, P_Me, 225, P_Mn, 226, P_Me, 229, P_Mn, 241, P_Cn,
     0, P_So, 2, P_Lu, 3, P_So, 7, P_Lu, 8, P_So, 10, P_Ll, 11, P_Lu, 14, P_Ll, 16, P_Lu, 19, P_Ll, 20, P_So, 21, P_Lu, 22, P_So, 24, P_Sm, 25, P_Lu, 30, P_So, 36, P_Lu, 37, P_So, 38, P_Lu, 39, P_So, 40, P_Lu, 41, P_So, 42, P_Lu, 46, P_So, 47, P_Ll, 48, P_Lu, 52, P_Ll, 53, P_Lo, 57, P_Ll, 58, P_So, 60, P_Ll, 62, P_Lu, 64, P_Sm, 69, P_Lul, 71, P_Ll, 74, P_So, 75, P_Sm, 76, P_So, 78, P_Ll, 79, P_So, 80, P_No, 96, P_Nl, 131, P_Lul, 133, P_Nl, 137, P_No, 138, P_So, 140, P_Cn, 144, P_Sm, 149, P_So, 154, P_Sm, 156, P_So, 160, P_Sm, 161, P_So, 163, P_Sm, 164, P_So, 166, P_Sm, 167, P_So, 174, P_Sm, 175, P_So, 206, P_Sm, 208, P_So, 210, P_Sm, 211, P_So, 212, P_Sm, 213, P_So, 244, P_Sm,
     0, P_Sm,
-    0, P_So, 8, P_Ps, 9, P_Pe, 10, P_Ps, 11, P_Pe, 12, P_So, 32, P_Sm, 34, P_So, 41, P_Ps, 42, P_Pe, 43, P_So, 124, P_Sm, 125, P_So, 155, P_Sm, 180, P_So, 220, P_Sm, 226, P_So, 251, P_Cn,
+    0, P_So, 8, P_Ps, 9, P_Pe, 10, P_Ps, 11, P_Pe, 12, P_So, 32, P_Sm, 34, P_So, 41, P_Ps, 42, P_Pe, 43, P_So, 124, P_Sm, 125, P_So, 155, P_Sm, 180, P_So, 220, P_Sm, 226, P_So, 255, P_Cn,
     0, P_So, 39, P_Cn, 64, P_So, 75, P_Cn, 96, P_No, 156, P_So, 234, P_No,
     0, P_So, 183, P_Sm, 184, P_So, 193, P_Sm, 194, P_So, 248, P_Sm,
     0, P_So, 111, P_Sm, 112, P_So,
@@ -61,7 +61,7 @@ const unsigned char UnicodeProperty::pro
     0, P_So, 48, P_Sm, 69, P_So, 71, P_Sm, 77, P_So, 116, P_Cn, 118, P_So, 150, P_Cn, 152, P_So, 186, P_Cn, 189, P_So, 201, P_Cn, 202, P_So, 210, P_Cn, 236, P_So, 240, P_Cn,
     0, P_Lu, 47, P_Cn, 48, P_Ll, 95, P_Cn, 96, P_Lul, 98, P_Lu, 101, P_Ll, 103, P_Lul, 109, P_Lu, 113, P_Ll, 114, P_Lul, 116, P_Ll, 117, P_Lul, 119, P_Ll, 124, P_Lm, 126, P_Lu, 129, P_Ll, 130, P_Lul, 228, P_Ll, 229, P_So, 235, P_Lul, 239, P_Mn, 242, P_Lul, 244, P_Cn, 249, P_Po, 253, P_No, 254, P_Po,
     0, P_Ll, 38, P_Cn, 39, P_Ll, 40, P_Cn, 45, P_Ll, 46, P_Cn, 48, P_Lo, 104, P_Cn, 111, P_Lm, 112, P_Po, 113, P_Cn, 127, P_Mn, 128, P_Lo, 151, P_Cn, 160, P_Lo, 167, P_Cn, 168, P_Lo, 175, P_Cn, 176, P_Lo, 183, P_Cn, 184, P_Lo, 191, P_Cn, 192, P_Lo, 199, P_Cn, 200, P_Lo, 207, P_Cn, 208, P_Lo, 215, P_Cn, 216, P_Lo, 223, P_Cn, 224, P_Mn,
-    0, P_Po, 2, P_Pi, 3, P_Pf, 4, P_Pi, 5, P_Pf, 6, P_Po, 9, P_Pi, 10, P_Pf, 11, P_Po, 12, P_Pi, 13, P_Pf, 14, P_Po, 23, P_Pd, 24, P_Po, 26, P_Pd, 27, P_Po, 28, P_Pi, 29, P_Pf, 30, P_Po, 32, P_Pi, 33, P_Pf, 34, P_Ps, 35, P_Pe, 36, P_Ps, 37, P_Pe, 38, P_Ps, 39, P_Pe, 40, P_Ps, 41, P_Pe, 42, P_Po, 47, P_Lm, 48, P_Po, 58, P_Pd, 60, P_Po, 64, P_Pd, 65, P_Po, 66, P_Ps, 67, P_Cn, 128, P_So, 154, P_Cn, 155, P_So, 244, P_Cn,
+    0, P_Po, 2, P_Pi, 3, P_Pf, 4, P_Pi, 5, P_Pf, 6, P_Po, 9, P_Pi, 10, P_Pf, 11, P_Po, 12, P_Pi, 13, P_Pf, 14, P_Po, 23, P_Pd, 24, P_Po, 26, P_Pd, 27, P_Po, 28, P_Pi, 29, P_Pf, 30, P_Po, 32, P_Pi, 33, P_Pf, 34, P_Ps, 35, P_Pe, 36, P_Ps, 37, P_Pe, 38, P_Ps, 39, P_Pe, 40, P_Ps, 41, P_Pe, 42, P_Po, 47, P_Lm, 48, P_Po, 58, P_Pd, 60, P_Po, 64, P_Pd, 65, P_Po, 66, P_Ps, 67, P_Po, 69, P_Cn, 128, P_So, 154, P_Cn, 155, P_So, 244, P_Cn,
     0, P_So, 214, P_Cn, 240, P_So, 252, P_Cn,
     0, P_Zs, 1, P_Po, 4, P_So, 5, P_Lm, 6, P_Lo, 7, P_Nl, 8, P_Ps, 9, P_Pe, 10, P_Ps, 11, P_Pe, 12, P_Ps, 13, P_Pe, 14, P_Ps, 15, P_Pe, 16, P_Ps, 17, P_Pe, 18, P_So, 20, P_Ps, 21, P_Pe, 22, P_Ps, 23, P_Pe, 24, P_Ps, 25, P_Pe, 26, P_Ps, 27, P_Pe, 28, P_Pd, 29, P_Ps, 30, P_Pe, 32, P_So, 33, P_Nl, 42, P_Mn, 46, P_Mc, 48, P_Pd, 49, P_Lm, 54, P_So, 56, P_Nl, 59, P_Lm, 60, P_Lo, 61, P_Po, 62, P_So, 64, P_Cn, 65, P_Lo, 151, P_Cn, 153, P_Mn, 155, P_Sk, 157, P_Lm, 159, P_Lo, 160, P_Pd, 161, P_Lo, 251, P_Po, 252, P_Lm, 255, P_Lo,
     0, P_Cn, 5, P_Lo, 46, P_Cn, 49, P_Lo, 143, P_Cn, 144, P_So, 146, P_No, 150, P_So, 160, P_Lo, 187, P_Cn, 192, P_So, 228, P_Cn, 240, P_Lo,
@@ -72,8 +72,8 @@ const unsigned char UnicodeProperty::pro
     0, P_Lo, 21, P_Lm, 22, P_Lo,
     0, P_Lo, 141, P_Cn, 144, P_So, 199, P_Cn, 208, P_Lo, 248, P_Lm, 254, P_Po,
     0, P_Lo, 12, P_Lm, 13, P_Po, 16, P_Lo, 32, P_Nd, 42, P_Lo, 44, P_Cn, 64, P_Lul, 110, P_Lo, 111, P_Mn, 112, P_Me, 115, P_Po, 116, P_Mn, 126, P_Po, 127, P_Lm, 128, P_Lul, 156, P_Lm, 158, P_Mn, 160, P_Lo, 230, P_Nl, 240, P_Mn, 242, P_Po, 248, P_Cn,
-    0, P_Sk, 23, P_Lm, 32, P_Sk, 34, P_Lul, 48, P_Ll, 50, P_Lul, 112, P_Lm, 113, P_Ll, 121, P_Lul, 125, P_Lu, 127, P_Ll, 128, P_Lul, 136, P_Lm, 137, P_Sk, 139, P_Lul, 143, P_Lo, 144, P_Lul, 148, P_Ll, 150, P_Lul, 170, P_Lu, 174, P_Cn, 176, P_Lu, 181, P_Ll, 182, P_Lul, 184, P_Cn, 247, P_Lo, 248, P_Lm, 250, P_Ll, 251, P_Lo,
-    0, P_Lo, 2, P_Mn, 3, P_Lo, 6, P_Mn, 7, P_Lo, 11, P_Mn, 12, P_Lo, 35, P_Mc, 37, P_Mn, 39, P_Mc, 40, P_So, 44, P_Cn, 48, P_No, 54, P_So, 56, P_Sc, 57, P_So, 58, P_Cn, 64, P_Lo, 116, P_Po, 120, P_Cn, 128, P_Mc, 130, P_Lo, 180, P_Mc, 196, P_Mn, 197, P_Cn, 206, P_Po, 208, P_Nd, 218, P_Cn, 224, P_Mn, 242, P_Lo, 248, P_Po, 251, P_Lo, 252, P_Po, 253, P_Lo, 254, P_Cn,
+    0, P_Sk, 23, P_Lm, 32, P_Sk, 34, P_Lul, 48, P_Ll, 50, P_Lul, 112, P_Lm, 113, P_Ll, 121, P_Lul, 125, P_Lu, 127, P_Ll, 128, P_Lul, 136, P_Lm, 137, P_Sk, 139, P_Lul, 143, P_Lo, 144, P_Lul, 148, P_Ll, 150, P_Lul, 170, P_Lu, 175, P_Cn, 176, P_Lu, 181, P_Ll, 182, P_Lul, 184, P_Cn, 247, P_Lo, 248, P_Lm, 250, P_Ll, 251, P_Lo,
+    0, P_Lo, 2, P_Mn, 3, P_Lo, 6, P_Mn, 7, P_Lo, 11, P_Mn, 12, P_Lo, 35, P_Mc, 37, P_Mn, 39, P_Mc, 40, P_So, 44, P_Cn, 48, P_No, 54, P_So, 56, P_Sc, 57, P_So, 58, P_Cn, 64, P_Lo, 116, P_Po, 120, P_Cn, 128, P_Mc, 130, P_Lo, 180, P_Mc, 196, P_Mn, 198, P_Cn, 206, P_Po, 208, P_Nd, 218, P_Cn, 224, P_Mn, 242, P_Lo, 248, P_Po, 251, P_Lo, 252, P_Po, 253, P_Lo, 254, P_Cn,
     0, P_Nd, 10, P_Lo, 38, P_Mn, 46, P_Po, 48, P_Lo, 71, P_Mn, 82, P_Mc, 84, P_Cn, 95, P_Po, 96, P_Lo, 125, P_Cn, 128, P_Mn, 131, P_Mc, 132, P_Lo, 179, P_Mn, 180, P_Mc, 182, P_Mn, 186, P_Mc, 188, P_Mn, 189, P_Mc, 193, P_Po, 206, P_Cn, 207, P_Lm, 208, P_Nd, 218, P_Cn, 222, P_Po, 224, P_Lo, 229, P_Mn, 230, P_Lm, 231, P_Lo, 240, P_Nd, 250, P_Lo, 255, P_Cn,
     0, P_Lo, 41, P_Mn, 47, P_Mc, 49, P_Mn, 51, P_Mc, 53, P_Mn, 55, P_Cn, 64, P_Lo, 67, P_Mn, 68, P_Lo, 76, P_Mn, 77, P_Mc, 78, P_Cn, 80, P_Nd, 90, P_Cn, 92, P_Po, 96, P_Lo, 112, P_Lm, 113, P_Lo, 119, P_So, 122, P_Lo, 123, P_Mc, 124, P_Mn, 125, P_Mc, 126, P_Lo, 176, P_Mn, 177, P_Lo, 178, P_Mn, 181, P_Lo, 183, P_Mn, 185, P_Lo, 190, P_Mn, 192, P_Lo, 193, P_Mn, 194, P_Lo, 195, P_Cn, 219, P_Lo, 221, P_Lm, 222, P_Po, 224, P_Lo, 235, P_Mc, 236, P_Mn, 238, P_Mc, 240, P_Po, 242, P_Lo, 243, P_Lm, 245, P_Mc, 246, P_Mn, 247, P_Cn,
     0, P_Cn, 1, P_Lo, 7, P_Cn, 9, P_Lo, 15, P_Cn, 17, P_Lo, 23, P_Cn, 32, P_Lo, 39, P_Cn, 40, P_Lo, 47, P_Cn, 48, P_Ll, 91, P_Sk, 92, P_Lm, 96, P_Ll, 102, P_Cn, 112, P_Ll, 192, P_Lo, 227, P_Mc, 229, P_Mn, 230, P_Mc, 232, P_Mn, 233, P_Mc, 235, P_Po, 236, P_Mc, 237, P_Mn, 238, P_Cn, 240, P_Nd, 250, P_Cn,
@@ -89,10 +89,10 @@ const unsigned char UnicodeProperty::pro
     0, P_Mn, 16, P_Po, 23, P_Ps, 24, P_Pe, 25, P_Po, 26, P_Cn, 32, P_Mn, 48, P_Po, 49, P_Pd, 51, P_Pc, 53, P_Ps, 54, P_Pe, 55, P_Ps, 56, P_Pe, 57, P_Ps, 58, P_Pe, 59, P_Ps, 60, P_Pe, 61, P_Ps, 62, P_Pe, 63, P_Ps, 64, P_Pe, 65, P_Ps, 66, P_Pe, 67, P_Ps, 68, P_Pe, 69, P_Po, 71, P_Ps, 72, P_Pe, 73, P_Po, 77, P_Pc, 80, P_Po, 83, P_Cn, 84, P_Po, 88, P_Pd, 89, P_Ps, 90, P_Pe, 91, P_Ps, 92, P_Pe, 93, P_Ps, 94, P_Pe, 95, P_Po, 98, P_Sm, 99, P_Pd, 100, P_Sm, 103, P_Cn, 104, P_Po, 105, P_Sc, 106, P_Po, 108, P_Cn, 112, P_Lo, 117, P_Cn, 118, P_Lo, 253, P_Cn, 255, P_Cf,
     0, P_Cn, 1, P_Po, 4, P_Sc, 5, P_Po, 8, P_Ps, 9, P_Pe, 10, P_Po, 11, P_Sm, 12, P_Po, 13, P_Pd, 14, P_Po, 16, P_Nd, 26, P_Po, 28, P_Sm, 31, P_Po, 33, P_Lu, 59, P_Ps, 60, P_Po, 61, P_Pe, 62, P_Sk, 63, P_Pc, 64, P_Sk, 65, P_Ll, 91, P_Ps, 92, P_Sm, 93, P_Pe, 94, P_Sm, 95, P_Ps, 96, P_Pe, 97, P_Po, 98, P_Ps, 99, P_Pe, 100, P_Po, 102, P_Lo, 112, P_Lm, 113, P_Lo, 158, P_Lm, 160, P_Lo, 191, P_Cn, 194, P_Lo, 200, P_Cn, 202, P_Lo, 208, P_Cn, 210, P_Lo, 216, P_Cn, 218, P_Lo, 221, P_Cn, 224, P_Sc, 226, P_Sm, 227, P_Sk, 228, P_So, 229, P_Sc, 231, P_Cn, 232, P_So, 233, P_Sm, 237, P_So, 239, P_Cn, 249, P_Cf, 252, P_So, 254, P_Cn,
     0, P_Lo, 12, P_Cn, 13, P_Lo, 39, P_Cn, 40, P_Lo, 59, P_Cn, 60, P_Lo, 62, P_Cn, 63, P_Lo, 78, P_Cn, 80, P_Lo, 94, P_Cn, 128, P_Lo, 251, P_Cn,
-    0, P_Po, 3, P_Cn, 7, P_No, 52, P_Cn, 55, P_So, 64, P_Nl, 117, P_No, 121, P_So, 138, P_No, 140, P_So, 141, P_Cn, 144, P_So, 156, P_Cn, 160, P_So, 161, P_Cn, 208, P_So, 253, P_Mn, 254, P_Cn,
+    0, P_Po, 3, P_Cn, 7, P_No, 52, P_Cn, 55, P_So, 64, P_Nl, 117, P_No, 121, P_So, 138, P_No, 140, P_So, 143, P_Cn, 144, P_So, 156, P_Cn, 160, P_So, 161, P_Cn, 208, P_So, 253, P_Mn, 254, P_Cn,
     0, P_Cn, 128, P_Lo, 157, P_Cn, 160, P_Lo, 209, P_Cn, 224, P_Mn, 225, P_No, 252, P_Cn,
     0, P_Lo, 32, P_No, 36, P_Cn, 48, P_Lo, 65, P_Nl, 66, P_Lo, 74, P_Nl, 75, P_Cn, 80, P_Lo, 118, P_Mn, 123, P_Cn, 128, P_Lo, 158, P_Cn, 159, P_Po, 160, P_Lo, 196, P_Cn, 200, P_Lo, 208, P_Po, 209, P_Nl, 214, P_Cn,
-    0, P_Lu, 40, P_Ll, 80, P_Lo, 158, P_Cn, 160, P_Nd, 170, P_Cn,
+    0, P_Lu, 40, P_Ll, 80, P_Lo, 158, P_Cn, 160, P_Nd, 170, P_Cn, 176, P_Lu, 212, P_Cn, 216, P_Ll, 252, P_Cn,
     0, P_Lo, 40, P_Cn, 48, P_Lo, 100, P_Cn, 111, P_Po, 112, P_Cn,
     0, P_Lo, 55, P_Cn, 64, P_Lo, 86, P_Cn, 96, P_Lo, 104, P_Cn,
     0, P_Lo, 6, P_Cn, 8, P_Lo, 9, P_Cn, 10, P_Lo, 54, P_Cn, 55, P_Lo, 57, P_Cn, 60, P_Lo, 61, P_Cn, 63, P_Lo, 86, P_Cn, 87, P_Po, 88, P_No, 96, P_Lo, 119, P_So, 121, P_No, 128, P_Lo, 159, P_Cn, 167, P_No, 176, P_Cn, 224, P_Lo, 243, P_Cn, 244, P_Lo, 246, P_Cn, 251, P_No,
@@ -103,14 +103,15 @@ const unsigned char UnicodeProperty::pro
     0, P_Cn, 96, P_No, 127, P_Cn,
     0, P_Mc, 1, P_Mn, 2, P_Mc, 3, P_Lo, 56, P_Mn, 71, P_Po, 78, P_Cn, 82, P_No, 102, P_Nd, 112, P_Cn, 127, P_Mn, 130, P_Mc, 131, P_Lo, 176, P_Mc, 179, P_Mn, 183, P_Mc, 185, P_Mn, 187, P_Po, 189, P_Cf, 190, P_Po, 194, P_Cn, 208, P_Lo, 233, P_Cn, 240, P_Nd, 250, P_Cn,
     0, P_Mn, 3, P_Lo, 39, P_Mn, 44, P_Mc, 45, P_Mn, 53, P_Cn, 54, P_Nd, 64, P_Po, 68, P_Cn, 80, P_Lo, 115, P_Mn, 116, P_Po, 118, P_Lo, 119, P_Cn, 128, P_Mn, 130, P_Mc, 131, P_Lo, 179, P_Mc, 182, P_Mn, 191, P_Mc, 193, P_Lo, 197, P_Po, 202, P_Mn, 205, P_Po, 206, P_Cn, 208, P_Nd, 218, P_Lo, 219, P_Po, 220, P_Lo, 221, P_Po, 224, P_Cn, 225, P_No, 245, P_Cn,
-    0, P_Lo, 18, P_Cn, 19, P_Lo, 44, P_Mc, 47, P_Mn, 50, P_Mc, 52, P_Mn, 53, P_Mc, 54, P_Mn, 56, P_Po, 62, P_Cn, 128, P_Lo, 135, P_Cn, 136, P_Lo, 137, P_Cn, 138, P_Lo, 142, P_Cn, 143, P_Lo, 158, P_Cn, 159, P_Lo, 169, P_Po, 170, P_Cn, 176, P_Lo, 223, P_Mn, 224, P_Mc, 227, P_Mn, 235, P_Cn, 240, P_Nd, 250, P_Cn,
+    0, P_Lo, 18, P_Cn, 19, P_Lo, 44, P_Mc, 47, P_Mn, 50, P_Mc, 52, P_Mn, 53, P_Mc, 54, P_Mn, 56, P_Po, 62, P_Mn, 63, P_Cn, 128, P_Lo, 135, P_Cn, 136, P_Lo, 137, P_Cn, 138, P_Lo, 142, P_Cn, 143, P_Lo, 158, P_Cn, 159, P_Lo, 169, P_Po, 170, P_Cn, 176, P_Lo, 223, P_Mn, 224, P_Mc, 227, P_Mn, 235, P_Cn, 240, P_Nd, 250, P_Cn,
     0, P_Mn, 2, P_Mc, 4, P_Cn, 5, P_Lo, 13, P_Cn, 15, P_Lo, 17, P_Cn, 19, P_Lo, 41, P_Cn, 42, P_Lo, 49, P_Cn, 50, P_Lo, 52, P_Cn, 53, P_Lo, 58, P_Cn, 60, P_Mn, 61, P_Lo, 62, P_Mc, 64, P_Mn, 65, P_Mc, 69, P_Cn, 71, P_Mc, 73, P_Cn, 75, P_Mc, 78, P_Cn, 80, P_Lo, 81, P_Cn, 87, P_Mc, 88, P_Cn, 93, P_Lo, 98, P_Mc, 100, P_Cn, 102, P_Mn, 109, P_Cn, 112, P_Mn, 117, P_Cn,
-    0, P_Cn, 128, P_Lo, 176, P_Mc, 179, P_Mn, 185, P_Mc, 186, P_Mn, 187, P_Mc, 191, P_Mn, 193, P_Mc, 194, P_Mn, 196, P_Lo, 198, P_Po, 199, P_Lo, 200, P_Cn, 208, P_Nd, 218, P_Cn,
+    0, P_Lo, 53, P_Mc, 56, P_Mn, 64, P_Mc, 66, P_Mn, 69, P_Mc, 70, P_Mn, 71, P_Lo, 75, P_Po, 80, P_Nd, 90, P_Cn, 91, P_Po, 92, P_Cn, 93, P_Po, 94, P_Cn, 128, P_Lo, 176, P_Mc, 179, P_Mn, 185, P_Mc, 186, P_Mn, 187, P_Mc, 191, P_Mn, 193, P_Mc, 194, P_Mn, 196, P_Lo, 198, P_Po, 199, P_Lo, 200, P_Cn, 208, P_Nd, 218, P_Cn,
     0, P_Cn, 128, P_Lo, 175, P_Mc, 178, P_Mn, 182, P_Cn, 184, P_Mc, 188, P_Mn, 190, P_Mc, 191, P_Mn, 193, P_Po, 216, P_Lo, 220, P_Mn, 222, P_Cn,
-    0, P_Lo, 48, P_Mc, 51, P_Mn, 59, P_Mc, 61, P_Mn, 62, P_Mc, 63, P_Mn, 65, P_Po, 68, P_Lo, 69, P_Cn, 80, P_Nd, 90, P_Cn, 128, P_Lo, 171, P_Mn, 172, P_Mc, 173, P_Mn, 174, P_Mc, 176, P_Mn, 182, P_Mc, 183, P_Mn, 184, P_Cn, 192, P_Nd, 202, P_Cn,
+    0, P_Lo, 48, P_Mc, 51, P_Mn, 59, P_Mc, 61, P_Mn, 62, P_Mc, 63, P_Mn, 65, P_Po, 68, P_Lo, 69, P_Cn, 80, P_Nd, 90, P_Cn, 96, P_Po, 109, P_Cn, 128, P_Lo, 171, P_Mn, 172, P_Mc, 173, P_Mn, 174, P_Mc, 176, P_Mn, 182, P_Mc, 183, P_Mn, 184, P_Cn, 192, P_Nd, 202, P_Cn,
     0, P_Lo, 26, P_Cn, 29, P_Mn, 32, P_Mc, 34, P_Mn, 38, P_Mc, 39, P_Mn, 44, P_Cn, 48, P_Nd, 58, P_No, 60, P_Po, 63, P_So, 64, P_Cn,
     0, P_Cn, 160, P_Lu, 192, P_Ll, 224, P_Nd, 234, P_No, 243, P_Cn, 255, P_Lo,
     0, P_Cn, 192, P_Lo, 249, P_Cn,
+    0, P_Lo, 9, P_Cn, 10, P_Lo, 47, P_Mc, 48, P_Mn, 55, P_Cn, 56, P_Mn, 62, P_Mc, 63, P_Mn, 64, P_Lo, 65, P_Po, 70, P_Cn, 80, P_Nd, 90, P_No, 109, P_Cn, 112, P_Po, 114, P_Lo, 144, P_Cn, 146, P_Mn, 168, P_Cn, 169, P_Mc, 170, P_Mn, 177, P_Mc, 178, P_Mn, 180, P_Mc, 181, P_Mn, 183, P_Cn,
     0, P_Lo, 154, P_Cn,
     0, P_Nl, 111, P_Cn, 112, P_Po, 117, P_Cn, 128, P_Lo,
     0, P_Lo, 68, P_Cn,
@@ -118,7 +119,9 @@ const unsigned char UnicodeProperty::pro
     0, P_Lo, 71, P_Cn,
     0, P_Lo, 57, P_Cn, 64, P_Lo, 95, P_Cn, 96, P_Nd, 106, P_Cn, 110, P_Po, 112, P_Cn, 208, P_Lo, 238, P_Cn, 240, P_Mn, 245, P_Po, 246, P_Cn,
     0, P_Lo, 48, P_Mn, 55, P_Po, 60, P_So, 64, P_Lm, 68, P_Po, 69, P_So, 70, P_Cn, 80, P_Nd, 90, P_Cn, 91, P_No, 98, P_Cn, 99, P_Lo, 120, P_Cn, 125, P_Lo, 144, P_Cn,
-    0, P_Lo, 69, P_Cn, 80, P_Lo, 81, P_Mc, 127, P_Cn, 143, P_Mn, 147, P_Lm, 160, P_Cn,
+    0, P_Lo, 69, P_Cn, 80, P_Lo, 81, P_Mc, 127, P_Cn, 143, P_Mn, 147, P_Lm, 160, P_Cn, 224, P_Lm, 225, P_Cn,
+    0, P_Cn, 236, P_Lo, 237, P_Cn,
+    0, P_Lo, 243, P_Cn,
     0, P_Lo, 2, P_Cn,
     0, P_Lo, 107, P_Cn, 112, P_Lo, 125, P_Cn, 128, P_Lo, 137, P_Cn, 144, P_Lo, 154, P_Cn, 156, P_So, 157, P_Mn, 159, P_Po, 160, P_Cf, 164, P_Cn,
     0, P_So, 246, P_Cn,
@@ -130,17 +133,18 @@ const unsigned char UnicodeProperty::pro
     0, P_Ll, 8, P_Lu, 34, P_Ll, 60, P_Lu, 86, P_Ll, 112, P_Lu, 138, P_Ll, 166, P_Cn, 168, P_Lu, 193, P_Sm, 194, P_Ll, 219, P_Sm, 220, P_Ll, 226, P_Lu, 251, P_Sm, 252, P_Ll,
     0, P_Ll, 21, P_Sm, 22, P_Ll, 28, P_Lu, 53, P_Sm, 54, P_Ll, 79, P_Sm, 80, P_Ll, 86, P_Lu, 111, P_Sm, 112, P_Ll, 137, P_Sm, 138, P_Ll, 144, P_Lu, 169, P_Sm, 170, P_Ll, 195, P_Sm, 196, P_Ll, 202, P_Lul, 204, P_Cn, 206, P_Nd,
     0, P_Mn, 55, P_So, 59, P_Mn, 109, P_So, 117, P_Mn, 118, P_So, 132, P_Mn, 133, P_So, 135, P_Po, 140, P_Cn, 155, P_Mn, 160, P_Cn, 161, P_Mn, 176, P_Cn,
+    0, P_Mn, 7, P_Cn, 8, P_Mn, 25, P_Cn, 27, P_Mn, 34, P_Cn, 35, P_Mn, 37, P_Cn, 38, P_Mn, 43, P_Cn,
     0, P_Lo, 197, P_Cn, 199, P_No, 208, P_Mn, 215, P_Cn,
+    0, P_Lu, 34, P_Ll, 68, P_Mn, 75, P_Cn, 80, P_Nd, 90, P_Cn, 94, P_Po, 96, P_Cn,
     0, P_Lo, 4, P_Cn, 5, P_Lo, 32, P_Cn, 33, P_Lo, 35, P_Cn, 36, P_Lo, 37, P_Cn, 39, P_Lo, 40, P_Cn, 41, P_Lo, 51, P_Cn, 52, P_Lo, 56, P_Cn, 57, P_Lo, 58, P_Cn, 59, P_Lo, 60, P_Cn, 66, P_Lo, 67, P_Cn, 71, P_Lo, 72, P_Cn, 73, P_Lo, 74, P_Cn, 75, P_Lo, 76, P_Cn, 77, P_Lo, 80, P_Cn, 81, P_Lo, 83, P_Cn, 84, P_Lo, 85, P_Cn, 87, P_Lo, 88, P_Cn, 89, P_Lo, 90, P_Cn, 91, P_Lo, 92, P_Cn, 93, P_Lo, 94, P_Cn, 95, P_Lo, 96, P_Cn, 97, P_Lo, 99, P_Cn, 100, P_Lo, 101, P_Cn, 103, P_Lo, 107, P_Cn, 108, P_Lo, 115, P_Cn, 116, P_Lo, 120, P_Cn, 121, P_Lo, 125, P_Cn, 126, P_Lo, 127, P_Cn, 128, P_Lo, 138, P_Cn, 139, P_Lo, 156, P_Cn, 161, P_Lo, 164, P_Cn, 165, P_Lo, 170, P_Cn, 171, P_Lo, 188, P_Cn, 240, P_Sm, 242, P_Cn,
     0, P_So, 44, P_Cn, 48, P_So, 148, P_Cn, 160, P_So, 175, P_Cn, 177, P_So, 192, P_Cn, 193, P_So, 208, P_Cn, 209, P_So, 246, P_Cn,
-    0, P_No, 13, P_Cn, 16, P_So, 47, P_Cn, 48, P_So, 108, P_Cn, 112, P_So, 155, P_Cn, 230, P_So,
-    0, P_So, 3, P_Cn, 16, P_So, 59, P_Cn, 64, P_So, 73, P_Cn, 80, P_So, 82, P_Cn,
+    0, P_No, 13, P_Cn, 16, P_So, 47, P_Cn, 48, P_So, 108, P_Cn, 112, P_So, 173, P_Cn, 230, P_So,
+    0, P_So, 3, P_Cn, 16, P_So, 60, P_Cn, 64, P_So, 73, P_Cn, 80, P_So, 82, P_Cn,
     0, P_So, 251, P_Sk,
-    0, P_So, 122, P_Cn, 123, P_So, 164, P_Cn, 165, P_So,
-    0, P_So, 209, P_Cn, 224, P_So, 237, P_Cn, 240, P_So, 244, P_Cn,
+    0, P_So, 211, P_Cn, 224, P_So, 237, P_Cn, 240, P_So, 247, P_Cn,
     0, P_So, 116, P_Cn, 128, P_So, 213, P_Cn,
     0, P_So, 12, P_Cn, 16, P_So, 72, P_Cn, 80, P_So, 90, P_Cn, 96, P_So, 136, P_Cn, 144, P_So, 174, P_Cn,
-    0, P_Cn, 16, P_So, 25, P_Cn, 128, P_So, 133, P_Cn, 192, P_So, 193, P_Cn,
+    0, P_Cn, 16, P_So, 31, P_Cn, 32, P_So, 40, P_Cn, 48, P_So, 49, P_Cn, 51, P_So, 63, P_Cn, 64, P_So, 76, P_Cn, 80, P_So, 95, P_Cn, 128, P_So, 146, P_Cn, 192, P_So, 193, P_Cn,
     0, P_Cn, 214, P_Lo, 215, P_Cn,
     0, P_Cn, 52, P_Lo, 53, P_Cn, 64, P_Lo, 65, P_Cn,
     0, P_Cn, 29, P_Lo, 30, P_Cn, 32, P_Lo, 33, P_Cn,
@@ -159,182 +163,191 @@ const unsigned int UnicodeProperty::prop
     0x500, 390, 450,
     0x600, 450, 520,
     0x700, 520, 560,
-    0x800, 560, 598,
-    0x900, 598, 720,
-    0xA00, 720, 870,
-    0xB00, 870, 1032,
-    0xC00, 1032, 1166,
-    0xD00, 1166, 1280,
-    0xE00, 1280, 1388,
-    0xF00, 1388, 1476,
-    0x1000, 1476, 1566,
-    0x1100, 1566, 1568,
-    0x1200, 1568, 1622,
-    0x1300, 1622, 1656,
-    0x1400, 1656, 1660,
-    0x1500, 1566, 1568,
-    0x1600, 1660, 1686,
-    0x1700, 1686, 1760,
-    0x1800, 1760, 1796,
-    0x1900, 1796, 1852,
-    0x1A00, 1852, 1916,
-    0x1B00, 1916, 1998,
-    0x1C00, 1998, 2060,
-    0x1D00, 2060, 2078,
-    0x1E00, 2078, 2084,
-    0x1F00, 2084, 2212,
-    0x2000, 2212, 2326,
-    0x2100, 2326, 2458,
-    0x2200, 2458, 2460,
-    0x2300, 2460, 2496,
-    0x2400, 2496, 2510,
-    0x2500, 2510, 2522,
-    0x2600, 2522, 2528,
-    0x2700, 2528, 2592,
-    0x2800, 2592, 2594,
-    0x2900, 2594, 2658,
-    0x2A00, 2458, 2460,
-    0x2B00, 2658, 2690,
-    0x2C00, 2690, 2744,
-    0x2D00, 2744, 2806,
-    0x2E00, 2806, 2890,
-    0x2F00, 2890, 2898,
-    0x3000, 2898, 3002,
-    0x3100, 3002, 3028,
-    0x3200, 3028, 3054,
-    0x3300, 2592, 2594,
-    0x3400, 3054, 3058,
+    0x800, 560, 606,
+    0x900, 606, 728,
+    0xA00, 728, 878,
+    0xB00, 878, 1040,
+    0xC00, 1040, 1174,
+    0xD00, 1174, 1290,
+    0xE00, 1290, 1398,
+    0xF00, 1398, 1486,
+    0x1000, 1486, 1576,
+    0x1100, 1576, 1578,
+    0x1200, 1578, 1632,
+    0x1300, 1632, 1666,
+    0x1400, 1666, 1670,
+    0x1500, 1576, 1578,
+    0x1600, 1670, 1696,
+    0x1700, 1696, 1770,
+    0x1800, 1770, 1810,
+    0x1900, 1810, 1866,
+    0x1A00, 1866, 1930,
+    0x1B00, 1930, 2012,
+    0x1C00, 2012, 2076,
+    0x1D00, 2076, 2094,
+    0x1E00, 2094, 2100,
+    0x1F00, 2100, 2228,
+    0x2000, 2228, 2342,
+    0x2100, 2342, 2474,
+    0x2200, 2474, 2476,
+    0x2300, 2476, 2512,
+    0x2400, 2512, 2526,
+    0x2500, 2526, 2538,
+    0x2600, 2538, 2544,
+    0x2700, 2544, 2608,
+    0x2800, 2608, 2610,
+    0x2900, 2610, 2674,
+    0x2A00, 2474, 2476,
+    0x2B00, 2674, 2706,
+    0x2C00, 2706, 2760,
+    0x2D00, 2760, 2822,
+    0x2E00, 2822, 2908,
+    0x2F00, 2908, 2916,
+    0x3000, 2916, 3020,
+    0x3100, 3020, 3046,
+    0x3200, 3046, 3072,
+    0x3300, 2608, 2610,
+    0x3400, 3072, 3076,
     0x3500, 0, 2,
-    0x4D00, 3058, 3066,
-    0x4E00, 3054, 3058,
+    0x4D00, 3076, 3084,
+    0x4E00, 3072, 3076,
     0x4F00, 0, 2,
-    0x9F00, 3066, 3072,
-    0xA000, 3072, 3078,
-    0xA100, 1566, 1568,
-    0xA400, 3078, 3092,
-    0xA500, 1566, 1568,
-    0xA600, 3092, 3138,
-    0xA700, 3138, 3196,
-    0xA800, 3196, 3266,
-    0xA900, 3266, 3332,
-    0xAA00, 3332, 3430,
-    0xAB00, 3430, 3488,
-    0xAC00, 3054, 3058,
+    0x9F00, 3084, 3090,
+    0xA000, 3090, 3096,
+    0xA100, 1576, 1578,
+    0xA400, 3096, 3110,
+    0xA500, 1576, 1578,
+    0xA600, 3110, 3156,
+    0xA700, 3156, 3214,
+    0xA800, 3214, 3284,
+    0xA900, 3284, 3350,
+    0xAA00, 3350, 3448,
+    0xAB00, 3448, 3506,
+    0xAC00, 3072, 3076,
     0xAD00, 0, 2,
-    0xD700, 3488, 3502,
-    0xD800, 3502, 3506,
+    0xD700, 3506, 3520,
+    0xD800, 3520, 3524,
     0xD900, 0, 2,
-    0xDB00, 3506, 3514,
-    0xDC00, 3502, 3506,
+    0xDB00, 3524, 3532,
+    0xDC00, 3520, 3524,
     0xDD00, 0, 2,
-    0xDF00, 3514, 3518,
-    0xE000, 3518, 3522,
+    0xDF00, 3532, 3536,
+    0xE000, 3536, 3540,
     0xE100, 0, 2,
-    0xF800, 3522, 3526,
-    0xF900, 1566, 1568,
-    0xFA00, 3526, 3534,
-    0xFB00, 3534, 3578,
-    0xFC00, 1566, 1568,
-    0xFD00, 3578, 3602,
-    0xFE00, 3602, 3712,
-    0xFF00, 3712, 3832,
-    0x10000, 3832, 3860,
-    0x10100, 3860, 3896,
-    0x10200, 3896, 3912,
-    0x10300, 3912, 3952,
-    0x10400, 3952, 3964,
-    0x10500, 3964, 3976,
-    0x10600, 1566, 1568,
-    0x10700, 3976, 3988,
-    0x10800, 3988, 4040,
-    0x10900, 4040, 4070,
-    0x10A00, 4070, 4136,
-    0x10B00, 4136, 4166,
-    0x10C00, 4166, 4180,
+    0xF800, 3540, 3544,
+    0xF900, 1576, 1578,
+    0xFA00, 3544, 3552,
+    0xFB00, 3552, 3596,
+    0xFC00, 1576, 1578,
+    0xFD00, 3596, 3620,
+    0xFE00, 3620, 3730,
+    0xFF00, 3730, 3850,
+    0x10000, 3850, 3878,
+    0x10100, 3878, 3914,
+    0x10200, 3914, 3930,
+    0x10300, 3930, 3970,
+    0x10400, 3970, 3990,
+    0x10500, 3990, 4002,
+    0x10600, 1576, 1578,
+    0x10700, 4002, 4014,
+    0x10800, 4014, 4066,
+    0x10900, 4066, 4096,
+    0x10A00, 4096, 4162,
+    0x10B00, 4162, 4192,
+    0x10C00, 4192, 4206,
     0x10D00, 0, 2,
-    0x10E00, 4180, 4186,
+    0x10E00, 4206, 4212,
     0x10F00, 0, 2,
-    0x11000, 4186, 4236,
-    0x11100, 4236, 4302,
-    0x11200, 4302, 4360,
-    0x11300, 4360, 4432,
-    0x11400, 4432, 4464,
-    0x11500, 4464, 4490,
-    0x11600, 4490, 4536,
-    0x11700, 4536, 4562,
-    0x11800, 4562, 4576,
+    0x11000, 4212, 4262,
+    0x11100, 4262, 4328,
+    0x11200, 4328, 4388,
+    0x11300, 4388, 4460,
+    0x11400, 4460, 4520,
+    0x11500, 4520, 4546,
+    0x11600, 4546, 4596,
+    0x11700, 4596, 4622,
+    0x11800, 4622, 4636,
     0x11900, 0, 2,
-    0x11A00, 4576, 4582,
+    0x11A00, 4636, 4642,
     0x11B00, 0, 2,
-    0x12000, 1566, 1568,
-    0x12300, 4582, 4586,
-    0x12400, 4586, 4596,
-    0x12500, 4596, 4600,
+    0x11C00, 4642, 4696,
+    0x11D00, 0, 2,
+    0x12000, 1576, 1578,
+    0x12300, 4696, 4700,
+    0x12400, 4700, 4710,
+    0x12500, 4710, 4714,
     0x12600, 0, 2,
-    0x13000, 1566, 1568,
-    0x13400, 4600, 4604,
+    0x13000, 1576, 1578,
+    0x13400, 4714, 4718,
     0x13500, 0, 2,
-    0x14400, 1566, 1568,
-    0x14600, 4604, 4608,
+    0x14400, 1576, 1578,
+    0x14600, 4718, 4722,
     0x14700, 0, 2,
-    0x16800, 1566, 1568,
-    0x16A00, 4608, 4634,
-    0x16B00, 4634, 4666,
+    0x16800, 1576, 1578,
+    0x16A00, 4722, 4748,
+    0x16B00, 4748, 4780,
     0x16C00, 0, 2,
-    0x16F00, 4666, 4682,
-    0x17000, 0, 2,
-    0x1B000, 4682, 4686,
+    0x16F00, 4780, 4800,
+    0x17000, 3072, 3076,
+    0x17100, 0, 2,
+    0x18700, 4800, 4806,
+    0x18800, 1576, 1578,
+    0x18A00, 4806, 4810,
+    0x18B00, 0, 2,
+    0x1B000, 4810, 4814,
     0x1B100, 0, 2,
-    0x1BC00, 4686, 4712,
+    0x1BC00, 4814, 4840,
     0x1BD00, 0, 2,
-    0x1D000, 4712, 4716,
-    0x1D100, 4716, 4746,
-    0x1D200, 4746, 4754,
-    0x1D300, 4754, 4762,
-    0x1D400, 4762, 4818,
-    0x1D500, 4818, 4872,
-    0x1D600, 4872, 4904,
-    0x1D700, 4904, 4946,
-    0x1D800, 2592, 2594,
-    0x1DA00, 4946, 4974,
+    0x1D000, 4840, 4844,
+    0x1D100, 4844, 4874,
+    0x1D200, 4874, 4882,
+    0x1D300, 4882, 4890,
+    0x1D400, 4890, 4946,
+    0x1D500, 4946, 5000,
+    0x1D600, 5000, 5032,
+    0x1D700, 5032, 5074,
+    0x1D800, 2608, 2610,
+    0x1DA00, 5074, 5102,
     0x1DB00, 0, 2,
-    0x1E800, 4974, 4984,
-    0x1E900, 0, 2,
-    0x1EE00, 4984, 5120,
+    0x1E000, 5102, 5122,
+    0x1E100, 0, 2,
+    0x1E800, 5122, 5132,
+    0x1E900, 5132, 5148,
+    0x1EA00, 0, 2,
+    0x1EE00, 5148, 5284,
     0x1EF00, 0, 2,
-    0x1F000, 5120, 5144,
-    0x1F100, 5144, 5162,
-    0x1F200, 5162, 5178,
-    0x1F300, 5178, 5182,
-    0x1F400, 2592, 2594,
-    0x1F500, 5182, 5192,
-    0x1F600, 5192, 5204,
-    0x1F700, 5204, 5212,
-    0x1F800, 5212, 5232,
-    0x1F900, 5232, 5246,
+    0x1F000, 5284, 5308,
+    0x1F100, 5308, 5326,
+    0x1F200, 5326, 5342,
+    0x1F300, 5342, 5346,
+    0x1F400, 2608, 2610,
+    0x1F600, 5346, 5358,
+    0x1F700, 5358, 5366,
+    0x1F800, 5366, 5386,
+    0x1F900, 5386, 5420,
     0x1FA00, 0, 2,
-    0x20000, 3054, 3058,
+    0x20000, 3072, 3076,
     0x20100, 0, 2,
-    0x2A600, 5246, 5252,
-    0x2A700, 3054, 3058,
+    0x2A600, 5420, 5426,
+    0x2A700, 3072, 3076,
     0x2A800, 0, 2,
-    0x2B700, 5252, 5262,
-    0x2B800, 5262, 5272,
+    0x2B700, 5426, 5436,
+    0x2B800, 5436, 5446,
     0x2B900, 0, 2,
-    0x2CE00, 5272, 5278,
+    0x2CE00, 5446, 5452,
     0x2CF00, 0, 2,
-    0x2F800, 1566, 1568,
-    0x2FA00, 5278, 5282,
+    0x2F800, 1576, 1578,
+    0x2FA00, 5452, 5456,
     0x2FB00, 0, 2,
-    0xE0000, 5282, 5292,
-    0xE0100, 5292, 5296,
+    0xE0000, 5456, 5466,
+    0xE0100, 5466, 5470,
     0xE0200, 0, 2,
-    0xF0000, 3518, 3522,
+    0xF0000, 3536, 3540,
     0xF0100, 0, 2,
-    0xFFF00, 5296, 5302,
-    0x100000, 3518, 3522,
+    0xFFF00, 5470, 5476,
+    0x100000, 3536, 3540,
     0x100100, 0, 2,
-    0x10FF00, 5296, 5302,
+    0x10FF00, 5470, 5476,
     0x110000, 0, 2,
 };
 const int UnicodeProperty::nproperty_offsets = (sizeof(UnicodeProperty::property_offsets) / (3*sizeof(unsigned int)));
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/uniprop.hh	2018-02-23 12:47:54.095971653 -0500
@@ -5,15 +5,15 @@
 class UnicodeProperty { public:
 
     enum {
-	P_C = 000, P_Cn = 000, P_Co = 001, P_Cs = 002, P_Cf = 003, P_Cc = 004,
-	P_Z = 010, P_Zs = 010, P_Zl = 011, P_Zp = 012,
-	P_M = 020, P_Mn = 020, P_Mc = 021, P_Me = 022,
-	P_L = 030, P_Lo = 030, P_Lu = 031, P_Ll = 032, P_Lt = 033, P_Lm = 034,
-	P_N = 040, P_No = 040, P_Nd = 041, P_Nl = 042,
-	P_P = 050, P_Po = 050, P_Pc = 051, P_Pd = 052, P_Ps = 053, P_Pe = 054, P_Pi = 055, P_Pf = 056,
-	P_S = 060, P_So = 060, P_Sm = 061, P_Sc = 062, P_Sk = 063,
-	P_TMASK = 0370,
-	P_MAX = 0377
+        P_C = 000, P_Cn = 000, P_Co = 001, P_Cs = 002, P_Cf = 003, P_Cc = 004,
+        P_Z = 010, P_Zs = 010, P_Zl = 011, P_Zp = 012,
+        P_M = 020, P_Mn = 020, P_Mc = 021, P_Me = 022,
+        P_L = 030, P_Lo = 030, P_Lu = 031, P_Ll = 032, P_Lt = 033, P_Lm = 034,
+        P_N = 040, P_No = 040, P_Nd = 041, P_Nl = 042,
+        P_P = 050, P_Po = 050, P_Pc = 051, P_Pd = 052, P_Ps = 053, P_Pe = 054, P_Pi = 055, P_Pf = 056,
+        P_S = 060, P_So = 060, P_Sm = 061, P_Sc = 062, P_Sk = 063,
+        P_TMASK = 0370,
+        P_MAX = 0377
     };
 
     static int property(uint32_t uni);
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.cc	2018-02-23 12:47:54.095971653 -0500
@@ -1,6 +1,6 @@
 /* util.{cc,hh} -- various bits
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -37,30 +37,30 @@ read_file(String filename, ErrorHandler
 {
     FILE *f;
     if (!filename || filename == "-") {
-	filename = "<stdin>";
-	f = stdin;
+        filename = "<stdin>";
+        f = stdin;
 #if defined(_MSDOS) || defined(_WIN32)
-	// Set the file mode to binary
-	_setmode(_fileno(f), _O_BINARY);
+        // Set the file mode to binary
+        _setmode(_fileno(f), _O_BINARY);
 #endif
     } else if (!(f = fopen(filename.c_str(), "rb"))) {
-	errh->xmessage((warning ? errh->e_warning : errh->e_error) + ErrorHandler::make_landmark_anno(filename), strerror(errno));
-	return String();
+        errh->xmessage((warning ? errh->e_warning : errh->e_error) + ErrorHandler::make_landmark_anno(filename), strerror(errno));
+        return String();
     }
 
     StringAccum sa;
     int amt;
     do {
-	if (char *x = sa.reserve(8192)) {
-	    amt = fread(x, 1, 8192, f);
-	    sa.adjust_length(amt);
-	} else
-	    amt = 0;
+        if (char *x = sa.reserve(8192)) {
+            amt = fread(x, 1, 8192, f);
+            sa.adjust_length(amt);
+        } else
+            amt = 0;
     } while (amt != 0);
     if (!feof(f) || ferror(f))
-	errh->xmessage((warning ? errh->e_warning : errh->e_error) + ErrorHandler::make_landmark_anno(filename), strerror(errno));
+        errh->xmessage((warning ? errh->e_warning : errh->e_error) + ErrorHandler::make_landmark_anno(filename), strerror(errno));
     if (f != stdin)
-	fclose(f);
+        fclose(f);
     return sa.take_string();
 }
 
@@ -68,9 +68,9 @@ String
 printable_filename(const String &s)
 {
     if (!s || s == "-")
-	return String::make_stable("<stdin>");
+        return String::make_stable("<stdin>");
     else
-	return s;
+        return s;
 }
 
 String
@@ -78,19 +78,19 @@ pathname_filename(const String &path)
 {
     int slash = path.find_right('/');
     if (slash >= 0 && slash != path.length() - 1)
-	return path.substring(slash + 1);
+        return path.substring(slash + 1);
     else
-	return path;
+        return path;
 }
 
 static String
 simplify_filename(String x)
 {
     while (x.substring(0, 2) == "./")
-	x = x.substring(2);
+        x = x.substring(2);
     int pos;
     while ((pos = x.find_left("/./")) >= 0)
-	x = x.substring(0, pos) + x.substring(pos + 2);
+        x = x.substring(0, pos) + x.substring(pos + 2);
     return x;
 }
 
@@ -104,7 +104,7 @@ String
 shell_quote(const String &str)
 {
     if (!str)
-	return String::make_stable("\"\"");
+        return String::make_stable("\"\"");
 
     const char *begin = str.begin();
     const char *end = str.end();
@@ -114,35 +114,35 @@ shell_quote(const String &str)
     sa.append('\"');
 
     for (const char *s = begin; s < end; ++s)
-	if (isalnum((unsigned char) *s) || *s == '_' || *s == '-' || *s == '+' || *s == '\\' || *s == ':' || *s == '.')
-	    /* do nothing */;
-	else if (*s == '\"') {
-	    sa.append(begin, s);
-	    sa.append("\"\"\"", 3);
-	    begin = s + 1;
-	} else {
-	    sa.append(begin, s + 1);
-	    begin = s + 1;
-	}
+        if (isalnum((unsigned char) *s) || *s == '_' || *s == '-' || *s == '+' || *s == '\\' || *s == ':' || *s == '.')
+            /* do nothing */;
+        else if (*s == '\"') {
+            sa.append(begin, s);
+            sa.append("\"\"\"", 3);
+            begin = s + 1;
+        } else {
+            sa.append(begin, s + 1);
+            begin = s + 1;
+        }
 
     if (sa.length() > 1) {
-	sa.append(begin, end);
-	sa.append('\"');
-	return sa.take_string();
+        sa.append(begin, end);
+        sa.append('\"');
+        return sa.take_string();
     }
 #else
     for (const char *s = begin; s < end; s++)
-	if (isalnum((unsigned char) *s) || *s == '_' || *s == '-' || *s == '+' || *s == '/' || *s == ':' || *s == '.')
-	    /* do nothing */;
-	else {
-	    sa.append(begin, s);
-	    sa.append('\\');
-	    begin = s;
-	}
+        if (isalnum((unsigned char) *s) || *s == '_' || *s == '-' || *s == '+' || *s == '/' || *s == ':' || *s == '.')
+            /* do nothing */;
+        else {
+            sa.append(begin, s);
+            sa.append('\\');
+            begin = s;
+        }
 
     if (sa.length()) {
-	sa.append(begin, end);
-	return sa.take_string();
+        sa.append(begin, end);
+        return sa.take_string();
     }
 #endif
 
@@ -153,12 +153,25 @@ int
 mysystem(const char *command, ErrorHandler *errh)
 {
     if (no_create) {
-	errh->message("would run %s", command);
-	return 0;
+        errh->message("would run %s", command);
+        return 0;
     } else {
-	if (verbose)
-	    errh->message("running %s", command);
-	return system(command);
+        if (verbose)
+            errh->message("running %s", command);
+        return system(command);
+    }
+}
+
+FILE*
+mypopen(const char* command, const char* type, ErrorHandler* errh)
+{
+    if (no_create) {
+        errh->message("would run %s", command);
+        return popen("true", type);
+    } else {
+        if (verbose)
+            errh->message("running %s", command);
+        return popen(command, type);
     }
 }
 
@@ -179,34 +192,34 @@ int
 temporary_file(String &filename, ErrorHandler *errh)
 {
     if (no_create)
-	return 0;		// random number suffices
+        return 0;               // random number suffices
 
 #if HAVE_MKSTEMP
     const char *tmpdir = getenv("TMPDIR");
     if (tmpdir)
-	filename = String(tmpdir) + "/otftotfm.XXXXXX";
+        filename = String(tmpdir) + "/otftotfm.XXXXXX";
     else {
 # ifdef P_tmpdir
-	filename = P_tmpdir "/otftotfm.XXXXXX";
+        filename = P_tmpdir "/otftotfm.XXXXXX";
 # else
-	filename = "/tmp/otftotfm.XXXXXX";
+        filename = "/tmp/otftotfm.XXXXXX";
 # endif
     }
     int fd = mkstemp(filename.mutable_c_str());
     if (fd < 0)
-	errh->error("temporary file %<%s%>: %s", filename.c_str(), strerror(errno));
+        errh->error("temporary file %<%s%>: %s", filename.c_str(), strerror(errno));
     return fd;
 #else  // !HAVE_MKSTEMP
     for (int tries = 0; tries < 5; tries++) {
-	if (!(filename = my_tmpnam()))
-	    return errh->error("cannot create temporary file");
+        if (!(filename = my_tmpnam()))
+            return errh->error("cannot create temporary file");
 # ifdef O_EXCL
-	int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0600);
+        int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0600);
 # else
-	int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600);
+        int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600);
 # endif
-	if (fd >= 0)
-	    return fd;
+        if (fd >= 0)
+            return fd;
     }
     return errh->error("temporary file %<%s%>: %s", filename.c_str(), strerror(errno));
 #endif
@@ -217,34 +230,34 @@ parse_unicode_number(const char* begin,
 {
     bool allow_lower = (require_prefix == 1);
     if (require_prefix < 0)
-	/* do not look for prefix */;
+        /* do not look for prefix */;
     else if (begin + 7 == end && begin[0] == 'u' && begin[1] == 'n' && begin[2] == 'i')
-	begin += 3;
+        begin += 3;
     else if (begin + 5 <= end && begin + 7 >= end && begin[0] == 'u')
-	begin++;
+        begin++;
     else if (begin + 3 <= end && begin + 8 >= end && begin[0] == 'U' && begin[1] == '+')
-	begin += 2, allow_lower = true;
+        begin += 2, allow_lower = true;
     else if (require_prefix > 1)
-	/* some prefix was required */
-	return false;
+        /* some prefix was required */
+        return false;
 
     uint32_t value;
     for (value = 0; begin < end; begin++)
-	if (*begin >= '0' && *begin <= '9')
-	    value = (value << 4) | (*begin - '0');
-	else if (*begin >= 'A' && *begin <= 'F')
-	    value = (value << 4) | (*begin - 'A' + 10);
-	else if (allow_lower && *begin >= 'a' && *begin <= 'f')
-	    value = (value << 4) | (*begin - 'a' + 10);
-	else
-	    return false;
+        if (*begin >= '0' && *begin <= '9')
+            value = (value << 4) | (*begin - '0');
+        else if (*begin >= 'A' && *begin <= 'F')
+            value = (value << 4) | (*begin - 'A' + 10);
+        else if (allow_lower && *begin >= 'a' && *begin <= 'f')
+            value = (value << 4) | (*begin - 'a' + 10);
+        else
+            return false;
 
     if (value > 0
-	&& (value <= 0xD7FF || (value >= 0xE000 && value <= 0x10FFFF))) {
-	result = value;
-	return true;
+        && (value <= 0xD7FF || (value >= 0xE000 && value <= 0x10FFFF))) {
+        result = value;
+        return true;
     } else
-	return false;
+        return false;
 }
 
 #if 0
@@ -253,7 +266,7 @@ shell_command_output(String cmdline, con
 {
     FILE *f = tmpfile();
     if (!f)
-	errh->fatal("cannot create temporary file: %s", strerror(errno));
+        errh->fatal("cannot create temporary file: %s", strerror(errno));
     ignore_result(fwrite(input.data(), 1, input.length(), f));
     fflush(f);
     rewind(f);
@@ -261,26 +274,26 @@ shell_command_output(String cmdline, con
     String new_cmdline = cmdline + " 0<&" + String(fileno(f));
     FILE *p = popen(new_cmdline.c_str(), "r");
     if (!p)
-	errh->fatal("%<%s%>: %s", cmdline.c_str(), strerror(errno));
+        errh->fatal("%<%s%>: %s", cmdline.c_str(), strerror(errno));
 
     StringAccum sa;
     int amt;
     do {
-	if (char *x = sa.reserve(2048)) {
-	    amt = fread(x, 1, 2048, p);
-	    sa.adjust_length(amt);
-	} else
-	    amt = 0;
+        if (char *x = sa.reserve(2048)) {
+            amt = fread(x, 1, 2048, p);
+            sa.adjust_length(amt);
+        } else
+            amt = 0;
     } while (amt != 0 && sa.length() < 200000);
     if (amt != 0)
-	errh->warning("%<%s%> output too long, truncated", cmdline.c_str());
+        errh->warning("%<%s%> output too long, truncated", cmdline.c_str());
     else if (!feof(p) || ferror(p))
-	errh->error("%<%s%>: %s", cmdline.c_str(), strerror(errno));
+        errh->error("%<%s%>: %s", cmdline.c_str(), strerror(errno));
 
     fclose(f);
     pclose(p);
     while (strip_newlines && sa && (sa.back() == '\n' || sa.back() == '\r'))
-	sa.pop_back();
+        sa.pop_back();
     return sa.take_string();
 }
 #endif
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.hh.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.hh
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.hh.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/otftotfm/util.hh	2018-02-23 12:47:54.095971653 -0500
@@ -2,6 +2,7 @@
 #define OTFTOTFM_UTIL_HH
 #include <lcdf/string.hh>
 #include <lcdf/globmatch.hh>
+#include <stdio.h>
 class ErrorHandler;
 
 extern bool no_create;
@@ -12,7 +13,7 @@ enum { G_ENCODING = 1, G_METRICS = 2, G_
        G_PSFONTSMAP = 16, G_BINARY = 32, G_ASCII = 64, G_DOTLESSJ = 128,
        G_UPDMAP = 256, G_TRUETYPE = 512, G_TYPE42 = 1024 };
 
-extern int output_flags;
+extern unsigned output_flags;
 
 String read_file(String filename, ErrorHandler *, bool warn = false);
 String printable_filename(const String &);
@@ -21,6 +22,7 @@ bool same_filename(const String &a, cons
 String shell_quote(const String &);
 int temporary_file(String &, ErrorHandler *);
 int mysystem(const char *command, ErrorHandler *);
+FILE* mypopen(const char* command, const char* type, ErrorHandler* errh);
 bool parse_unicode_number(const char*, const char*, int require_prefix, uint32_t& result);
 
 #ifdef WIN32
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/README.md.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/README.md
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/README.md.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/README.md	2018-02-23 12:47:54.095971653 -0500
@@ -99,7 +99,7 @@ named `FONTNAME.afm` -- `MyriadMM-LightC
 Copyright and license
 ---------------------
 
-All source code is Copyright (c) 1997-2016 Eddie Kohler.
+All source code is Copyright (c) 1997-2018 Eddie Kohler.
 
 This code is distributed under the GNU General Public License, Version 2
 (and only Version 2). The GNU General Public License is available via the
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.1	2018-02-23 12:47:54.096971628 -0500
@@ -1,4 +1,4 @@
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1dotlessj/t1dotlessj.cc	2018-02-23 12:47:54.096971628 -0500
@@ -1,6 +1,6 @@
 /* t1dotlessj.cc -- driver for creating dotlessj characters from Type 1 fonts
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -317,7 +317,7 @@ main(int argc, char *argv[])
 
 	  case VERSION_OPT:
 	    printf("t1dotlessj (LCDF typetools) %s\n", VERSION);
-	    printf("Copyright (C) 2003-2016 Eddie Kohler\n\
+	    printf("Copyright (C) 2003-2018 Eddie Kohler\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");
@@ -410,10 +410,10 @@ particular purpose.\n");
     // write it to output
     if (!outputf)
 	outputf = stdout;
+    if (binary) {
 #if defined(_MSDOS) || defined(_WIN32)
-    _setmode(_fileno(outputf), _O_BINARY);
+	_setmode(_fileno(outputf), _O_BINARY);
 #endif
-    if (binary) {
 	Type1PFBWriter w(outputf);
 	dotless_font->write(w);
     } else {
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/cscheck.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/cscheck.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/cscheck.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/cscheck.cc	2018-02-23 12:47:54.096971628 -0500
@@ -1,6 +1,6 @@
 /* cscheck.{cc,hh} -- checking Type 1 charstrings for validity
  *
- * Copyright (c) 1999-2016 Eddie Kohler
+ * Copyright (c) 1999-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.1	2018-02-23 12:47:54.096971628 -0500
@@ -1,4 +1,4 @@
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1lint/t1lint.cc	2018-02-23 12:47:54.096971628 -0500
@@ -1,6 +1,6 @@
 /* t1lint.cc -- driver for checking Type 1 fonts for validity
  *
- * Copyright (c) 1999-2016 Eddie Kohler
+ * Copyright (c) 1999-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -412,7 +412,7 @@ main(int argc, char *argv[])
 
      case VERSION_OPT:
       printf("t1lint (LCDF typetools) %s\n", VERSION);
-      printf("Copyright (C) 1999-2016 Eddie Kohler\n\
+      printf("Copyright (C) 1999-2018 Eddie Kohler\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");
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.1	2018-02-23 12:47:54.096971628 -0500
@@ -1,4 +1,4 @@
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1rawafm/t1rawafm.cc	2018-02-23 12:47:54.096971628 -0500
@@ -1,6 +1,6 @@
 /* t1rawafm.cc -- driver for generating a raw AFM file from a font
  *
- * Copyright (c) 2008-2016 Eddie Kohler
+ * Copyright (c) 2008-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -315,7 +315,7 @@ main(int argc, char *argv[])
 
           case VERSION_OPT:
             printf("t1rawafm (LCDF typetools) %s\n", VERSION);
-            printf("Copyright (C) 2008-2016 Eddie Kohler\n\
+            printf("Copyright (C) 2008-2018 Eddie Kohler\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");
@@ -359,9 +359,6 @@ particular purpose.\n");
         if (!outf)
             errh->fatal("%s: %s", output_file, strerror(errno));
     }
-#if defined(_MSDOS) || defined(_WIN32)
-    _setmode(_fileno(outf), _O_BINARY);
-#endif
 
     write_afm(outf, font);
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.1	2018-02-23 12:47:54.097971603 -0500
@@ -1,4 +1,4 @@
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/t1reencode.cc	2018-02-23 12:47:54.097971603 -0500
@@ -1,6 +1,6 @@
 /* t1reencode.cc -- driver for reencoding Type 1 fonts
  *
- * Copyright (c) 2005-2016 Eddie Kohler
+ * Copyright (c) 2005-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -978,7 +978,7 @@ main(int argc, char *argv[])
 
 	  case VERSION_OPT:
 	    printf("t1reencode (LCDF typetools) %s\n", VERSION);
-	    printf("Copyright (C) 1999-2016 Eddie Kohler\n\
+	    printf("Copyright (C) 1999-2018 Eddie Kohler\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");
@@ -1094,10 +1094,10 @@ particular purpose.\n");
 	if (!outf)
 	    errh->fatal("%s: %s", output_file, strerror(errno));
     }
+    if (binary) {
 #if defined(_MSDOS) || defined(_WIN32)
-    _setmode(_fileno(outf), _O_BINARY);
+	_setmode(_fileno(outf), _O_BINARY);
 #endif
-    if (binary) {
 	Type1PFBWriter w(outf);
 	font->write(w);
     } else {
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/util.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/util.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/util.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1reencode/util.cc	2018-02-23 12:47:54.097971603 -0500
@@ -1,6 +1,6 @@
 /* util.{cc,hh} -- various bits
  *
- * Copyright (c) 2003-2016 Eddie Kohler
+ * Copyright (c) 2003-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.1	2018-02-23 12:47:54.097971603 -0500
@@ -1,4 +1,4 @@
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/t1testpage/t1testpage.cc	2018-02-23 12:47:54.097971603 -0500
@@ -1,6 +1,6 @@
 /* t1testpage.cc -- driver for generating Type 1 fonts' test pages
  *
- * Copyright (c) 1999-2016 Eddie Kohler
+ * Copyright (c) 1999-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -624,7 +624,7 @@ main(int argc, char *argv[])
 
 	  case VERSION_OPT:
 	    printf("t1testpage (LCDF typetools) %s\n", VERSION);
-	    printf("Copyright (C) 1999-2016 Eddie Kohler\n\
+	    printf("Copyright (C) 1999-2018 Eddie Kohler\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");
@@ -665,9 +665,6 @@ particular purpose.\n");
 	if (!outf)
 	    errh->fatal("%s: %s", output_file, strerror(errno));
     }
-#if defined(_MSDOS) || defined(_WIN32)
-    _setmode(_fileno(outf), _O_BINARY);
-#endif
 
     //font->undo_synthetic();
 
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.1.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.1
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.1.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.1	2018-02-23 12:47:54.097971603 -0500
@@ -1,4 +1,4 @@
-.ds V 2.106
+.ds V 2.107
 .de M
 .BR "\\$1" "(\\$2)\\$3"
 ..
diff -up texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.cc.git4166ff9 texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.cc
--- texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.cc.git4166ff9	2016-11-25 13:08:53.000000000 -0500
+++ texlive-base-20170520/source/texk/lcdf-typetools/lcdf-typetools-src/ttftotype42/ttftotype42.cc	2018-02-23 12:47:54.098971578 -0500
@@ -1,6 +1,6 @@
 /* ttftotype42.cc -- driver for translating TrueType fonts to Type 42 fonts
  *
- * Copyright (c) 2006-2016 Eddie Kohler
+ * Copyright (c) 2006-2018 Eddie Kohler
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -355,7 +355,7 @@ main(int argc, char *argv[])
 
 	  case VERSION_OPT:
 	    printf("ttftotype42 (LCDF typetools) %s\n", VERSION);
-	    printf("Copyright (C) 2006-2016 Eddie Kohler\n\
+	    printf("Copyright (C) 2006-2018 Eddie Kohler\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");
