#include <stdio.h>
#include <limits.h>
#include <time.h>
#include <c-fopen.h>

typedef unsigned char   TTF_BYTE;
typedef signed char     TTF_CHAR;
typedef unsigned short  TTF_USHORT;
typedef signed short    TTF_SHORT;
typedef unsigned long   TTF_ULONG;
typedef signed long     TTF_LONG;
typedef unsigned long   TTF_FIXED;
typedef unsigned short  TTF_FUNIT;
typedef signed short    TTF_FWORD;
typedef unsigned short  TTF_UFWORD;
typedef unsigned short  TTF_F2DOT14;

typedef struct _dirtab_entry {
    char tag[4];
    TTF_ULONG checksum;
    TTF_ULONG offset;
    TTF_ULONG length;
} dirtab_entry;

typedef struct {
    TTF_ULONG wx;
    char *name;
    TTF_USHORT index;
    TTF_LONG bbox[4];
    TTF_LONG offset;
    char used;
} mtx_entry;

typedef struct _kern_entry {
    TTF_FWORD value;
    TTF_USHORT adjacent;
    struct _kern_entry *next;
} kern_entry;

#define TTF_BYTE_SIZE       1
#define TTF_CHAR_SIZE       1
#define TTF_USHORT_SIZE     2
#define TTF_SHORT_SIZE      2
#define TTF_ULONG_SIZE      4
#define TTF_LONG_SIZE       4
#define TTF_FIXED_SIZE      4
#define TTF_FWORD_SIZE      2
#define TTF_UFWORD_SIZE     2
#define TTF_F2DOT14_SIZE    2

#define GET_TYPE(t)  	((t)getnum(t##_SIZE))

#define GET_BYTE()      GET_TYPE(TTF_BYTE)
#define GET_CHAR()      GET_TYPE(TTF_CHAR)
#define GET_USHORT()    GET_TYPE(TTF_USHORT)
#define GET_SHORT()     GET_TYPE(TTF_SHORT)
#define GET_ULONG()     GET_TYPE(TTF_ULONG)
#define GET_LONG()      GET_TYPE(TTF_LONG)
#define GET_FIXED()     GET_TYPE(TTF_FIXED)
#define GET_FUNIT()     GET_TYPE(TTF_FUNIT)
#define GET_FWORD()     GET_TYPE(TTF_FWORD)
#define GET_UFWORD()    GET_TYPE(TTF_UFWORD)
#define GET_F2DOT14()   GET_TYPE(TTF_F2DOT14)

#define NTABS           24
#define AND             ,

#define FAIL(S) do {                                       \
    fprintf(stderr, "Error: ");                            \
    if (filename != 0)                                     \
        fprintf(stderr, "file `%s': ", filename);          \
    fprintf(stderr, S);                                    \
    fprintf(stderr, "\n");                                 \
    _exit(-1);                                             \
} while (0)

#define WARN(S) do {                                       \
    fprintf(stderr, "Warning: ");                          \
    if (filename != 0)                                     \
        fprintf(stderr, "file `%s': ", filename);          \
    fprintf(stderr, S);                                    \
    fprintf(stderr, "\n");                                 \
} while (0)

#define CHECK_BUF(size, buf_size)                          \
    if ((size) >= buf_size - 2)                            \
        FAIL("buffer overflow [%i bytes]" AND buf_size)

#define APPEND_CHAR_TO_BUF(c, p, buf, buf_size) do {       \
    if (c == 9)                                            \
        c = 32;                                            \
    if (c == 13 || c == EOF)                               \
        c = 10;                                            \
    if (c != ' ' || (p > buf && p[-1] != 32)) {            \
        CHECK_BUF(p - buf, buf_size);                      \
        *p++ = c;                                          \
    }                                                      \
} while (0)

#define APPEND_EOL(p, buf, buf_size) do {                  \
    if (p - buf > 1 && p[-1] != 10) {                      \
        CHECK_BUF(p - buf, buf_size);                      \
        *p++ = 10;                                         \
    }                                                      \
    if (p - buf > 2 && p[-2] == 32) {                      \
        p[-2] = 10;                                        \
        p--;                                               \
    }                                                      \
    *p = 0;                                                \
} while (0)

#define READ_FIELD(r, q, buf) do {                         \
    for (q = buf; *r != 32 && *r != 10; *q++ = *r++);      \
    *q = 0;                                                \
    if (*r == 32)                                          \
        r++;                                               \
} while (0)

#define XTALLOC(n, t) ((t *) xmalloc ((n) * sizeof (t)))
#define XFREE(p)        if (!p) free(p)

#define NMACGLYPHS      258
#define MAX_CHAR_NUM    256
#define ENC_BUF_SIZE    1024

#define ENC_GETCHAR()   xgetc(encfile)
#define ENC_EOF()       feof(encfile)

#define SKIP(n)         getnum(n)
#define PRINT_STR(S)    if (S != 0) printf(#S " %s\n", S)
#define PRINT_NUM(N)    if (N != 0) printf(#N " %i\n", N)

#define TTF_FUNIT(n) \
    (n < 0 ? -((-n/upem)*1000 + ((-n%upem)*1000)/upem) :\
    ((n/upem)*1000 + ((n%upem)*1000)/upem))

char *FontName = 0;
char *FullName = 0;
char *Notice = 0;
TTF_LONG ItalicAngle = 0;
TTF_LONG IsFixedPitch = 0;
TTF_LONG FontBBox1 = 0;
TTF_LONG FontBBox2 = 0;
TTF_LONG FontBBox3 = 0;
TTF_LONG FontBBox4 = 0;
TTF_LONG UnderlinePosition = 0;
TTF_LONG UnderlineThickness = 0;
TTF_LONG CapHeight = 0;
TTF_LONG XHeight = 0;
TTF_LONG Ascender = 0;
TTF_LONG Descender = 0;

char *filename = 0;
FILE *fontfile, *encfile;

TTF_USHORT upem;
TTF_USHORT ntabs;
int nhmtx;
int post_format;
int loca_format;
int nglyphs;
int nkernpairs = 0;
int names_count = 0;
char *ps_glyphs_buf = 0;
dirtab_entry *dir_tab;
mtx_entry *mtx_tab;
kern_entry *kern_tab;
char *enc_names[MAX_CHAR_NUM];
short enc_index[MAX_CHAR_NUM];

char notdef[] = ".notdef";

char *mac_glyph[NMACGLYPHS] = {
notdef, ".null", "CR", "space", "exclam", "quotedbl", "numbersign", "dollar",
"percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk",
"plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three",
"four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
"equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
"underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring",
"Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave",
"acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave",
"ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
"ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute",
"ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
"section", "bullet", "paragraph", "germandbls", "registered", "copyright",
"trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity",
"plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "Sigma",
"Pi", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae",
"oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin",
"approxequal", "Delta", "guillemotleft", "guillemotright", "ellipsis",
"nbspace", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash",
"quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
"lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft",
"guilsinglright", "fi", "fl", "daggerdbl", "middot", "quotesinglbase",
"quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute",
"Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave",
"Oacute", "Ocircumflex", "applelogo", "Ograve", "Uacute", "Ucircumflex",
"Ugrave", "dotlessi", "circumflex", "tilde", "overscore", "breve",
"dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash",
"lslash", "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
"Yacute", "yacute", "Thorn", "thorn", "minus", "multiply", "onesuperior",
"twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters",
"franc", "Gbreve", "gbreve", "Idot", "Scedilla", "scedilla", "Cacute",
"cacute", "Ccaron", "ccaron", "dmacron"
};

void *xmalloc(unsigned size)
{
    void *p = (void *)malloc(size);
    if (p == 0)
        FAIL("malloc() failed (%u bytes)" AND size);
    return p;
}

FILE *xfopen(char *name, char *mode)
{
    FILE *f = fopen(name, mode);
    if (f == 0)
        FAIL("fopen() failed");
    return f;
}

void xfclose(FILE *f)
{
  if (fclose (f) != 0)
        FAIL("fclose() failed");
}

long xftell(FILE *f)
{
    long offset = ftell(f);
    if (offset < 0)
        FAIL("ftell() failed");
    return offset;
}

int xgetc(FILE *stream)
{
    int c = getc(stream);
    if (c < 0 && c != EOF)
        FAIL("getc() failed");
    return c;
}

char *xstrdup(char *s)
{
    char *p = XTALLOC(strlen(s) + 1, char);
    return strcpy(p, s);
}

long getnum(int s)
{
    long i = 0;
    int c;
    while (s > 0) {
        if ((c = xgetc(fontfile)) < 0)
            FAIL("unexpected EOF");
        i = (i << 8) + c;
        s--;
    }
    return i;
}

dirtab_entry *name_lookup(char *s)
{
    dirtab_entry *p;
    for (p = dir_tab; p - dir_tab < ntabs; p++)
        if (strncmp(p->tag, s, 4) == 0)
            break;
    if (p - dir_tab == ntabs)
        p = 0;
    return p;
}

void seek_tab(char *name, TTF_LONG offset)
{
    dirtab_entry *p = name_lookup(name);
    if (p == 0)
        FAIL("can't find table `%s'" AND name);
    if (fseek(fontfile, p->offset + offset, SEEK_SET) < 0)
        FAIL("fseek() failed while reading `%s' table" AND name);
}

void seek_off(char *name, TTF_LONG offset)
{
    if (fseek(fontfile, offset, SEEK_SET) < 0)
        FAIL("fseek() failed while reading `%s' table" AND name);
}

void store_kern_value(TTF_USHORT i, TTF_USHORT j, TTF_FWORD v)
{
    kern_entry *pk;
    for (pk = kern_tab + i; pk->next != 0; pk = pk->next);
    pk->next = XTALLOC(1, kern_entry);
    pk = pk->next;
    pk->next = 0;
    pk->adjacent = j;
    pk->value = v;
}

TTF_FWORD get_kern_value(TTF_USHORT i, TTF_USHORT j)
{
    kern_entry *pk;
    for (pk = kern_tab + i; pk->next != 0; pk = pk->next)
        if (pk->adjacent == j)
            return pk->value;
    return 0;
}

void free_tabs()
{
    int i;
    kern_entry *p, *q, *r;
    XFREE(ps_glyphs_buf);
    XFREE(dir_tab);
    XFREE(mtx_tab);
    for (i = 0; i < MAX_CHAR_NUM; i++)
        if (enc_names[i] != notdef)
            free(enc_names[i]);
    for (p = kern_tab; p - kern_tab < nglyphs; p++)
        if (p->next != 0) {
            for (q = p->next; q != 0; q = r) {
                r = q->next;
                free(q);
            }
        }
    XFREE(kern_tab);
}

void read_encoding(char *encname)
{
    char enc_line[ENC_BUF_SIZE], buf[ENC_BUF_SIZE], *p, *q, *r;
    int c, i;
    filename = encname;
    if ((encfile = xfopen(encname, FOPEN_RBIN_MODE)) == 0)
        FAIL("can't open encoding file for reading");
    for (;;) {
        p = enc_line;
        do {
            c = ENC_GETCHAR();
            APPEND_CHAR_TO_BUF(c, p, enc_line, ENC_BUF_SIZE);
        } while (c != 10);
        APPEND_EOL(p, enc_line, ENC_BUF_SIZE);
        if (p - enc_line > 1 && *enc_line == '/')
            break; /* we suppose this line to contain the name of encoding vector */
        if (ENC_EOF())
            FAIL("unexpected end of file");
    }
    for (i = 0; i < MAX_CHAR_NUM; i++)
        enc_names[i] = notdef;
    for (;;) {
        p = enc_line;
        do {
            c = ENC_GETCHAR();
            APPEND_CHAR_TO_BUF(c, p, enc_line, ENC_BUF_SIZE);
        } while (c != 10);
        APPEND_EOL(p, enc_line, ENC_BUF_SIZE);
        if (p - enc_line <= 1 || *enc_line == '%')
            continue;
        if (strncmp(enc_line, "] def", strlen("] def")) == 0) {
            xfclose(encfile);
            return;
        }
        else if (ENC_EOF())
            FAIL("unexpected end of file");
        r = enc_line;
        do {
            if (*r == '%')
                break;
            READ_FIELD(r, q, buf);
            if (strcmp(buf + 1, notdef) != 0) /* skip the slash */ {
                enc_names[names_count] = xstrdup(buf + 1);
            }
            if (names_count++ >= MAX_CHAR_NUM)
                FAIL("encoding vector contains more than %i names" AND
                     MAX_CHAR_NUM);
        } while (*r != 10);
    }
}

void read_font()
{
    long i, j, k, l, n;
    TTF_FWORD kern_value;
    char buf[1024], *p;
    dirtab_entry *pd;
    kern_entry *pk;
    mtx_entry *pm;
    SKIP(TTF_FIXED_SIZE);
    ntabs = GET_USHORT();
    SKIP(3*TTF_USHORT_SIZE);
    dir_tab = XTALLOC(ntabs, dirtab_entry);
    for (pd = dir_tab; pd - dir_tab < ntabs; pd++) {
        pd->tag[0] = GET_CHAR();
        pd->tag[1] = GET_CHAR();
        pd->tag[2] = GET_CHAR();
        pd->tag[3] = GET_CHAR();
        SKIP(TTF_ULONG_SIZE);
        pd->offset = GET_ULONG();
        pd->length = GET_ULONG();
    }
    seek_tab("head", 2*TTF_FIXED_SIZE + 2*TTF_ULONG_SIZE + TTF_USHORT_SIZE);
    upem = GET_USHORT();
    SKIP(16);
    FontBBox1 = GET_FWORD();
    FontBBox2 = GET_FWORD();
    FontBBox3 = GET_FWORD();
    FontBBox4 = GET_FWORD();
    SKIP(TTF_USHORT_SIZE);
    SKIP(TTF_USHORT_SIZE + TTF_SHORT_SIZE);
    loca_format = GET_SHORT();
    seek_tab("maxp", TTF_FIXED_SIZE);
    nglyphs = GET_USHORT();
    mtx_tab = XTALLOC(nglyphs, mtx_entry);
    for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) {
        pm->name = 0;
        pm->used = 0;
    }
    seek_tab("hhea", TTF_FIXED_SIZE);
    Ascender = GET_FWORD();
    Descender = GET_FWORD();
    SKIP(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3*TTF_FWORD_SIZE + 8*TTF_SHORT_SIZE);
    nhmtx = GET_USHORT();
    seek_tab("hmtx", 0);
    for (pm = mtx_tab; pm - mtx_tab < nhmtx; pm++) {
        pm->wx = GET_UFWORD();
        SKIP(TTF_FWORD_SIZE);
    }
    i = pm[-1].wx;
    for (; pm - mtx_tab < nglyphs; pm++)
        pm->wx = i;
    seek_tab("post", 0);
    post_format = GET_FIXED();
    ItalicAngle = GET_FIXED();
    UnderlinePosition = GET_FWORD();
    UnderlineThickness = GET_FWORD();
    IsFixedPitch = GET_ULONG();
    SKIP(4*TTF_ULONG_SIZE);
    switch (post_format) {
    case 0x00010000:
        for (pm = mtx_tab; pm - mtx_tab < NMACGLYPHS; pm++)
            pm->name = mac_glyph[pm - mtx_tab];
        for (;pm - mtx_tab < nglyphs; pm++)
            pm->name = notdef;
        break;
    case 0x00018000:
        for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
            pm->name = mac_glyph[GET_CHAR()];
        break;
    case 0x00020000:
        l = GET_USHORT(); /* some fonts have this value different from nglyphs */
        for (pm = mtx_tab; pm - mtx_tab < l; pm++)
            pm->index = GET_USHORT();
        if ((pd = name_lookup("post")) == 0)
            FAIL("can't find table `post'");
        n = pd->length - (xftell(fontfile) - pd->offset);
        ps_glyphs_buf = XTALLOC(n + 1, char);
        for (p = ps_glyphs_buf; p - ps_glyphs_buf < n;) {
            for (i = GET_BYTE(); i > 0; i--)
                *p++ = GET_CHAR();
            *p++ = 0;
        }
        for (pm = mtx_tab; pm - mtx_tab < l; pm++) {
            if (pm->index < NMACGLYPHS)
                pm->name = mac_glyph[pm->index];
            else {
                k = pm->index - NMACGLYPHS;
                for (p = ps_glyphs_buf; k > 0; k--)
                    p = (char *)strchr(p, 0) + 1;
                pm->name = p;
            }
        }
        break;
    default:
        FAIL("unsupported format (%8X) of `post' table" AND post_format);
    }
    seek_tab("loca", 0);
    for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
        pm->offset = (loca_format == 1 ? GET_ULONG() : GET_USHORT() << 1);
    if ((pd = name_lookup("glyf")) == 0)
        FAIL("can't find table `glyf'");
    for (n = pd->offset, pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
        if (pm->offset != (pm - 1)->offset) {
            seek_off("glyf", n + pm->offset);
            SKIP(TTF_SHORT_SIZE);
            pm->bbox[0] = GET_FWORD();
            pm->bbox[1] = GET_FWORD();
            pm->bbox[2] = GET_FWORD();
            pm->bbox[3] = GET_FWORD();
        }
        else {
            pm->bbox[0] = 0;
            pm->bbox[1] = 0;
            pm->bbox[2] = 0;
            pm->bbox[3] = 0;
        }
    seek_tab("name", TTF_USHORT_SIZE);
    i = ftell(fontfile);
    n = GET_USHORT();
    j = GET_USHORT() + i - TTF_USHORT_SIZE;
    i += 2*TTF_USHORT_SIZE;
    while (n-- > 0) {
        seek_off("name", i + 3*TTF_USHORT_SIZE);
        k = GET_USHORT();
        l = GET_USHORT();
        if (k == 0 || k == 4 || k == 6) {
            seek_off("name", j + GET_USHORT());
            for (p = buf; l-- > 0; p++)
                *p = GET_CHAR();
            *p++ = 0;
            p = xstrdup(buf);
            switch (k) {
            case 0:  Notice = p; break;
            case 4:  FullName = p; break;
            case 6:  FontName = p; break;
            }
            if (Notice != 0 && FullName != 0 && FontName != 0)
                break;
        }
        i += 6*TTF_USHORT_SIZE;
    }
    if ((pd = name_lookup("PCLT")) != 0) {
        seek_off("PCLT", pd->offset + TTF_FIXED_SIZE + TTF_ULONG_SIZE + TTF_USHORT_SIZE);
        XHeight = GET_USHORT();
        SKIP(2*TTF_USHORT_SIZE);
        CapHeight = GET_USHORT();
    }
    if ((pd = name_lookup("kern")) == 0)
        return;
    kern_tab = XTALLOC(nglyphs, kern_entry);
    for (pk = kern_tab; pk - kern_tab < nglyphs; pk++) {
        pk->next = 0;
        pk->value = 0;
    }
    seek_off("kern", pd->offset + TTF_USHORT_SIZE);
    for (n = GET_USHORT(); n > 0; n--) {
        SKIP(2*TTF_USHORT_SIZE);
        k = GET_USHORT();
        if (!(k & 1) || (k & 2) || (k & 4))
            return;
        if (k >> 8 != 0) {
            fprintf(stderr, "warning: only format 0 supported of `kern' \
            subtables, others are ignored\n");
            continue;
        }
        k = GET_USHORT();
        SKIP(3*TTF_USHORT_SIZE);
        while (k-- > 0) {
            i = GET_USHORT();
            j = GET_USHORT();
            kern_value = GET_FWORD();
            if (kern_value != 0) {
                store_kern_value(i, j, kern_value);
                nkernpairs++;
            }
        }
    }
}

void print_afm(char *date, char *fontname)
{
    int i, j;
    mtx_entry *pm;
    TTF_FWORD kern_value;
    int new_nkernpairs;
    short *idx;
    char **pe;
    kern_entry *pk, *qk;
    printf("Comment Converted at %s by ttf2afm from font file `%s'", date, fontname);
    printf("\nStartFontMetrics 2.0\n");
    PRINT_STR(FontName);
    PRINT_STR(FullName);
    PRINT_STR(Notice);
    printf("ItalicAngle %i", ItalicAngle/0x10000);
    if (ItalicAngle%0x10000 > 0)
        printf(".%i", ((ItalicAngle%0x10000)*1000)/0x10000);
    printf("\n");
    printf("IsFixedPitch %s\n", IsFixedPitch ? "true" : "false");
    printf("FontBBox %i %i %i %i\n", TTF_FUNIT(FontBBox1), TTF_FUNIT(FontBBox2),
    TTF_FUNIT(FontBBox3), TTF_FUNIT(FontBBox4));
    PRINT_NUM(UnderlinePosition);
    PRINT_NUM(UnderlineThickness);
    PRINT_NUM(CapHeight);
    PRINT_NUM(XHeight);
    PRINT_NUM(Ascender);
    PRINT_NUM(Descender);
    if (names_count == 0) {
        printf("\nStartCharMetrics %u\n", nglyphs);
        for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
            if (pm->name != 0)
                printf("C %d ; WX %i ; N %s ; B %i %i %i %i ;\n", 
                i < 256 ? i : -1,
                TTF_FUNIT(pm->wx), 
                pm->name,
                TTF_FUNIT(pm->bbox[0]),
                TTF_FUNIT(pm->bbox[1]),
                TTF_FUNIT(pm->bbox[2]),
                TTF_FUNIT(pm->bbox[3]));
    }
    else {
        i = 0;
        for (pe = enc_names; pe - enc_names < names_count; pe++) {
            if (*pe == notdef)
                continue;
            for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++)
                if (pm->name != 0)
                    if (strcmp(*pe, pm->name) == 0)
                        break;
            if (pm - mtx_tab < nglyphs) {
                i++;
                pm->used = 1;
                enc_index[pe - enc_names] = pm - mtx_tab;
            }
            else
                WARN("glyph `%s' not found" AND *pe);
        }
        printf("\nStartCharMetrics %u\n", i);
        for (idx = enc_index, pe = enc_names; pe - enc_names < names_count; 
        idx++, pe++)
            if (*idx > 0 && (mtx_tab + *idx)->used > 0)
                printf("C %d ; WX %i ; N %s ; B %i %i %i %i ;\n", 
                pe - enc_names, 
                TTF_FUNIT((mtx_tab + *idx)->wx), 
                (mtx_tab + *idx)->name,
                TTF_FUNIT((mtx_tab + *idx)->bbox[0]),
                TTF_FUNIT((mtx_tab + *idx)->bbox[1]),
                TTF_FUNIT((mtx_tab + *idx)->bbox[2]),
                TTF_FUNIT((mtx_tab + *idx)->bbox[3]));
    }
    printf("EndCharMetrics\n");
    if (nkernpairs == 0)
        goto end_afm;
    if (names_count != 0) {
        new_nkernpairs = 0;
        for (pk = kern_tab; pk - kern_tab < nglyphs; pk++)
            if (mtx_tab[pk-kern_tab].used)
                for (qk = pk; qk != 0; qk = qk->next)
                    if (qk->value != 0 && mtx_tab[qk->adjacent].used)
                        new_nkernpairs++;
        printf("\nStartKernData\nStartKernPairs %i\n", new_nkernpairs);
        for (pk = kern_tab; pk - kern_tab < nglyphs; pk++)
            if (mtx_tab[pk-kern_tab].used)
                for (qk = pk; qk != 0; qk = qk->next)
                    if (qk->value != 0 && mtx_tab[qk->adjacent].used)
                        printf("KPX %s %s %i\n", mtx_tab[pk-kern_tab].name, 
                                mtx_tab[qk->adjacent].name, 
                                TTF_FUNIT(qk->value));
    }
    else {
        printf("\nStartKernData\nStartKernPairs %i\n", nkernpairs);
        for (pk = kern_tab; pk - kern_tab < nglyphs; pk++)
            for (qk = pk; qk != 0; qk = qk->next)
                if (qk->value != 0)
                    printf("KPX %s %s %i\n", mtx_tab[pk-kern_tab].name, 
                            mtx_tab[qk->adjacent].name, 
                            TTF_FUNIT(qk->value));
    }
    printf("EndKernPairs\nEndKernData\n");
end_afm:
    printf("EndFontMetrics\n");
}

main(int argc, char **argv)
{
    char date[128];
    time_t t = time(&t);
    mtx_entry *pm;
    int i;
    if (argc < 2)
        FAIL("Font file name missing\nUsage: ttf2afm fontname [encodingfile]");
    filename = argv[1];
    sprintf(date, "%s\n", ctime(&t));
    *(char *)strchr(date, '\n') = 0;
    if ((fontfile = fopen(argv[1], FOPEN_RBIN_MODE)) == 0)
        FAIL("can't open font file for reading");
    if (argc > 2) {
        filename = argv[2];
        read_encoding(argv[2]);
        filename = argv[1];
    }
    read_font();
    print_afm(date, argv[1]);
    XFREE(Notice);
    XFREE(FullName);
    XFREE(FontName);
    xfclose(fontfile);
    return 0;
}
