home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 613a.lha / pfm2afm_v1.0 / src / pfm2afm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-09  |  20.2 KB  |  661 lines

  1. /********************************************************************
  2.  *                                                                  *
  3.  *  Title:  pfm2afm - Convert Windows .pfm files to .afm files      *
  4.  *                                                                  *
  5.  *  Author: Ken Borgendale   10/9/91  Version 1.0                   *
  6.  *                                                                  *
  7.  *  Function:                                                       *
  8.  *      Convert a Windows .pfm (Printer Font Metrics) file to a     *
  9.  *      .afm (Adobe Font Metrics) file.  The purpose of this is     *
  10.  *      to allow fonts put out for Windows to be used with OS/2.    *
  11.  *                                                                  *
  12.  *  Syntax:                                                         *
  13.  *      pfm2afm  infile  [outfile] -a                               *
  14.  *                                                                  *
  15.  *  Copyright:                                                      *
  16.  *      pfm2afm - Copyright (C) IBM Corp., 1991                     *
  17.  *                                                                  *
  18.  *      This code is released for public use as long as the         *
  19.  *      copyright remains intact.  This code is provided asis       *
  20.  *      without any warrenties, express or implied.                 *
  21.  *                                                                  *
  22.  *  Notes:                                                          *
  23.  *      1. Much of the information in the original .afm file is     *
  24.  *         lost when the .pfm file is created, and thus cannot be   *
  25.  *         reconstructed by this utility.  This is especially true  *
  26.  *         of data for characters not in the Windows character set. *
  27.  *                                                                  *
  28.  *      2. This module is coded to be compiled by the MSC 6.0.      *
  29.  *         For other compilers, be careful of the packing of the    *
  30.  *         PFM structure.                                           *
  31.  *                                                                  *
  32.  ********************************************************************/
  33.  
  34. #include <libraries/dos.h>  /* For the return code #defines */
  35.  
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <stdlib.h>
  39. #include <ctype.h>
  40.  
  41. #include "pfm2afm.h"
  42.  
  43. #define BUFSIZE 4096
  44.  
  45. /*
  46.  *  Function Prototypes
  47.  */
  48. VOID    help        (VOID);
  49. VOID    parseargs   (int, UBYTE **);
  50. VOID    openpfm     (VOID);
  51. VOID    openafm     (VOID);
  52. VOID    putheader   (VOID);
  53. VOID    putchartab  (VOID);
  54. VOID    outchar     (int, UWORD, UBYTE *);
  55. VOID    putkerntab  (KERN *, UWORD);
  56. VOID    puttrailer  (VOID);
  57. VOID    outval      (int);
  58. VOID    revbyt      (UBYTE *, int);
  59.  
  60. /*
  61.  *  GLOBAL VARIABLES
  62.  */
  63. FILE   *inf;                 /* INPUT FILE        */
  64. FILE   *outf;                /* OUTPUT FILE       */
  65. UBYTE   mmsg[256];           /* BUFFER FOR MSGS   */
  66. UBYTE   infname[272];        /* INPUT FILE NAME   */
  67. UBYTE   outfname[272];       /* OUTPUT FILE NAME  */
  68. UBYTE   buffer[BUFSIZE];     /* .PFM READ BUFFER  */
  69. PFM     pfm;                 /* .PFM HEADER       */
  70. PSX     psx;                 /* METRICS EXTENSION */
  71.  
  72. UBYTE   debugflag;           /* DEBUG INFORMATION FLAG */
  73. UBYTE   allflag;
  74. UBYTE   isMono;              /* Font is mono-spaced */
  75.  
  76. /*
  77.  *  DO THE FUNCTION
  78.  */
  79. int main(argc, argv)
  80. int      argc;
  81. UBYTE         *argv[];
  82. {
  83.     UWORD pairs;
  84.  
  85.     /* PARSE ARGUMENTS */
  86.     parseargs(argc, argv);
  87.  
  88.     /* OPEN AND CHECK INPUT FILE */
  89.     openpfm();
  90.  
  91.     /* MAKE OUTPUT FILE NAME AND OPEN */
  92.     openafm();
  93.  
  94.     /* PUT OUT HEADER INFORMATION */
  95.     putheader();
  96.  
  97.     /* PUT OUT CHARACTER TABLE */
  98.     putchartab();
  99.  
  100.     /* PUT OUT KERNING TABLE */
  101.     if (pfm.kernpairs)
  102.     {   memcpy(&pairs, buffer+pfm.kernpairs, sizeof(pairs));
  103.         revbyt((UBYTE *)&pairs, sizeof(pairs));
  104.         putkerntab((KERN *)(buffer+pfm.kernpairs+2), pairs);
  105.     }
  106.  
  107.     /* PUT OUT TRAILER LINE */
  108.     puttrailer();
  109.  
  110.     return(RETURN_OK);
  111. }
  112.  
  113. /*
  114.  *  PUT OUT NORMAL HELP
  115.  */
  116. VOID  help (VOID)
  117. {
  118.     puts("\nPFM2AFM - Convert Windows .PFM to .AFM - Version 1.0\n");
  119.     puts("This utility converts Windows .PFM files for Adobe type 1 fonts");
  120.     puts("to .AFM files for use on OS/2.  This allows fonts created for");
  121.     puts("Windows, and shipped without the .AFM file to be used on OS/2.\n");
  122.     puts("PFM2AFM  infile  [outfile]  -opts");
  123.     puts("    The extension .PFM is added to the infile if it has none.");
  124.     puts("    The outfile is defaulted from the input file name.");
  125.     puts("    -a = All codepoints in range\n");
  126.     puts("Note that .PFM files are missing some of the data necessary to");
  127.     puts("construct .AFM files, so the conversion may not be perfect.\n");
  128.     puts("Ken Borgendale  -  kwb@betasvm2.vnet.ibm.com\n");
  129.     puts("Ported to Amiga by Kevin Ross  -  GEnie: K.ROSS12  BIX: kross\n");
  130.     exit (RETURN_WARN);
  131. }
  132.  
  133.  
  134. /*
  135.  *  Parse arguments.  This is the full arg treatment, which is sort of
  136.  *  overkill for one option, but it allows more to be added later.
  137.  */
  138. VOID  parseargs (argc, argv)
  139. int              argc;
  140. UBYTE                 *argv[];
  141. {
  142.     UBYTE swchar, *argp;
  143.     int argcnt, filecnt;
  144.  
  145.     argcnt = 1;
  146.     filecnt = 0;
  147.  
  148.     /* READ THE ARGUMENTS AND DECIDE WHAT WE ARE DOING */
  149.     while (argcnt<argc)
  150.     {   argp = argv[argcnt];
  151.  
  152.         switch(argp[0])
  153.         {
  154.             /* PROCESS SWITCHES.  FILES MAY NOT START WITH '-' */
  155.             case OPTSEP:
  156.                 swchar = (UBYTE)tolower(argp[1]);
  157.                 argp += 2;
  158.                 switch (swchar)
  159.                 {
  160.                     /* ALL CODEPOINTS */
  161.                     case 'a':
  162.                         allflag = 0;
  163.                         break;
  164.  
  165.                     /* DEBUG OPTION */
  166.                     case 'd':
  167.                         debugflag = 1;
  168.                         break;
  169.  
  170.                     default:
  171.                         fputs("Unknown option: ", stderr);
  172.                         fputs(argp-2, stderr);
  173.                         fputc('\n', stderr);
  174.                 }
  175.                 break;
  176.  
  177.             case '?':
  178.                 help();      /* DOES NOT RETURN */
  179.  
  180.             default:
  181.                 switch(++filecnt)
  182.                 {   case 1:
  183.                         strcpy(infname, argp);
  184.                         break;
  185.                     case 2:
  186.                         strcpy(outfname, argp);
  187.                         break;
  188.                     default:
  189.                         fputs("Extra parameter ignored: ", stderr);
  190.                         fputs(argp, stderr);
  191.                         fputc('\n', stderr);
  192.                 }
  193.         }
  194.         argcnt++;
  195.     }
  196.  
  197.     /* WE REQUIRE THE INPUT FILE NAME */
  198.     if (!filecnt)
  199.         help();
  200. }
  201.  
  202.  
  203. /*
  204.  *  OPEN THE .PFM FILE AND CHECK IT
  205.  */
  206. VOID  openpfm(VOID)
  207. {
  208.     UBYTE *cp;
  209.     int len;
  210.  
  211.     /* CHECK FOR A FILE EXTENSION */
  212.     cp = infname + strlen(infname) - 1;
  213.     while (cp >= infname && *cp != '.' && *cp != '/' && *cp != ':')
  214.         cp--;
  215.     if (*cp != '.')
  216.         strcat(infname, ".pfm");
  217.  
  218.     /* OPEN THE FILE */
  219.     inf = fopen(infname, "rb");
  220.     if (!inf)
  221.     {   strcpy(mmsg, "Unable to open input file \"");
  222.         strcat(mmsg, infname);
  223.         strcat(mmsg, "\"");
  224.         perror(mmsg);
  225.         exit(RETURN_ERROR);
  226.     }
  227.  
  228.     /* READ THE FILE */
  229.     len = fread(buffer, 1, BUFSIZE, inf);
  230.     if (len < 256 || len == BUFSIZE)
  231.     {   strcpy(mmsg, "Input file \"");
  232.         strcat(mmsg, infname);
  233.         strcat(mmsg, "\" read error");
  234.         perror(mmsg);
  235.         exit(RETURN_ERROR);
  236.     }
  237.  
  238.     /* UNPACK RECORD INTO PFM STRUCT */
  239.     cp = buffer;
  240.     memcpy(&pfm.vers,      cp, sizeof(pfm.vers));      cp += sizeof(pfm.vers);
  241.     memcpy(&pfm.len,       cp, sizeof(pfm.len));       cp += sizeof(pfm.len);
  242.     memcpy(&pfm.copyright, cp, sizeof(pfm.copyright)); cp += sizeof(pfm.copyright);
  243.     memcpy(&pfm.type,      cp, sizeof(pfm.type));      cp += sizeof(pfm.type);
  244.     memcpy(&pfm.points,    cp, sizeof(pfm.points));    cp += sizeof(pfm.points);
  245.     memcpy(&pfm.verres,    cp, sizeof(pfm.verres));    cp += sizeof(pfm.verres);
  246.     memcpy(&pfm.horres,    cp, sizeof(pfm.horres));    cp += sizeof(pfm.horres);
  247.     memcpy(&pfm.ascent,    cp, sizeof(pfm.ascent));    cp += sizeof(pfm.ascent);
  248.     memcpy(&pfm.intleading,cp, sizeof(pfm.intleading));cp += sizeof(pfm.intleading);
  249.     memcpy(&pfm.extleading,cp, sizeof(pfm.extleading));cp += sizeof(pfm.extleading);
  250.     memcpy(&pfm.italic,    cp, sizeof(pfm.italic));    cp += sizeof(pfm.italic);
  251.     memcpy(&pfm.uline,     cp, sizeof(pfm.uline));     cp += sizeof(pfm.uline);
  252.     memcpy(&pfm.overs,     cp, sizeof(pfm.overs));     cp += sizeof(pfm.overs);
  253.     memcpy(&pfm.weight,    cp, sizeof(pfm.weight));    cp += sizeof(pfm.weight);
  254.     memcpy(&pfm.charset,   cp, sizeof(pfm.charset));   cp += sizeof(pfm.charset);
  255.     memcpy(&pfm.pixwidth,  cp, sizeof(pfm.pixwidth));  cp += sizeof(pfm.pixwidth);
  256.     memcpy(&pfm.pixheight, cp, sizeof(pfm.pixheight)); cp += sizeof(pfm.pixheight);
  257.     memcpy(&pfm.kind,      cp, sizeof(pfm.kind));      cp += sizeof(pfm.kind);
  258.     memcpy(&pfm.avgwidth,  cp, sizeof(pfm.avgwidth));  cp += sizeof(pfm.avgwidth);
  259.     memcpy(&pfm.maxwidth,  cp, sizeof(pfm.maxwidth));  cp += sizeof(pfm.maxwidth);
  260.     memcpy(&pfm.firstchar, cp, sizeof(pfm.firstchar)); cp += sizeof(pfm.firstchar);
  261.     memcpy(&pfm.lastchar,  cp, sizeof(pfm.lastchar));  cp += sizeof(pfm.lastchar);
  262.     memcpy(&pfm.defchar,   cp, sizeof(pfm.defchar));   cp += sizeof(pfm.defchar);
  263.     memcpy(&pfm.brkchar,   cp, sizeof(pfm.brkchar));   cp += sizeof(pfm.brkchar);
  264.     memcpy(&pfm.widthby,   cp, sizeof(pfm.widthby));   cp += sizeof(pfm.widthby);
  265.     memcpy(&pfm.device,    cp, sizeof(pfm.device));    cp += sizeof(pfm.device);
  266.     memcpy(&pfm.face,      cp, sizeof(pfm.face));      cp += sizeof(pfm.face);
  267.     memcpy(&pfm.bits,      cp, sizeof(pfm.bits));      cp += sizeof(pfm.bits);
  268.     memcpy(&pfm.bitoff,    cp, sizeof(pfm.bitoff));    cp += sizeof(pfm.bitoff);
  269.     memcpy(&pfm.extlen,    cp, sizeof(pfm.extlen));    cp += sizeof(pfm.extlen);
  270.     memcpy(&pfm.psext,     cp, sizeof(pfm.psext));     cp += sizeof(pfm.psext);
  271.     memcpy(&pfm.chartab,   cp, sizeof(pfm.chartab));   cp += sizeof(pfm.chartab);
  272.     cp += sizeof(pfm.res1);
  273.     memcpy(&pfm.kernpairs, cp, sizeof(pfm.kernpairs)); cp += sizeof(pfm.kernpairs);
  274.     cp += sizeof(pfm.res2);
  275.     memcpy(&pfm.fontname,  cp, sizeof(pfm.fontname));  cp += sizeof(pfm.fontname);
  276.  
  277.     /*
  278.      *  Adjust ordering of bytes in binary values
  279.      *  68000 orders values MSB to LSB  --  8086 orders values LSB to MSB
  280.      */
  281.     revbyt((UBYTE *)&pfm.vers,       sizeof(pfm.vers));
  282.     revbyt((UBYTE *)&pfm.len,        sizeof(pfm.len));
  283.     revbyt((UBYTE *)&pfm.type,       sizeof(pfm.type));
  284.     revbyt((UBYTE *)&pfm.points,     sizeof(pfm.points));
  285.     revbyt((UBYTE *)&pfm.verres,     sizeof(pfm.verres));
  286.     revbyt((UBYTE *)&pfm.horres,     sizeof(pfm.horres));
  287.     revbyt((UBYTE *)&pfm.ascent,     sizeof(pfm.ascent));
  288.     revbyt((UBYTE *)&pfm.intleading, sizeof(pfm.intleading));
  289.     revbyt((UBYTE *)&pfm.extleading, sizeof(pfm.extleading));
  290.     revbyt((UBYTE *)&pfm.weight,     sizeof(pfm.weight));
  291.     revbyt((UBYTE *)&pfm.pixwidth,   sizeof(pfm.pixwidth));
  292.     revbyt((UBYTE *)&pfm.pixheight,  sizeof(pfm.pixheight));
  293.     revbyt((UBYTE *)&pfm.avgwidth,   sizeof(pfm.avgwidth));
  294.     revbyt((UBYTE *)&pfm.maxwidth,   sizeof(pfm.maxwidth));
  295.     revbyt((UBYTE *)&pfm.widthby,    sizeof(pfm.widthby));
  296.     revbyt((UBYTE *)&pfm.device,     sizeof(pfm.device));
  297.     revbyt((UBYTE *)&pfm.face,       sizeof(pfm.face));
  298.     revbyt((UBYTE *)&pfm.bits,       sizeof(pfm.bits));
  299.     revbyt((UBYTE *)&pfm.bitoff,     sizeof(pfm.bitoff));
  300.     revbyt((UBYTE *)&pfm.extlen,     sizeof(pfm.extlen));
  301.     revbyt((UBYTE *)&pfm.psext,      sizeof(pfm.psext));
  302.     revbyt((UBYTE *)&pfm.chartab,    sizeof(pfm.chartab));
  303.     revbyt((UBYTE *)&pfm.kernpairs,  sizeof(pfm.kernpairs));
  304.     revbyt((UBYTE *)&pfm.fontname,   sizeof(pfm.fontname));
  305.  
  306.     /* DO CONSISTENCY CHECK */
  307.     if (len != (int)pfm.len    /* CHECK LENGTH FIELD MATCHES FILE LENGTH */
  308.     && pfm.extlen != 30        /* CHECK LENGTH OF PostScript EXTENSION   */
  309.     && pfm.fontname > 75 && pfm.fontname < 512)   /* FONT NAME SPECIFIED */
  310.     {   fputs("Not a valid Windows type 1 .PFM file - ", stderr);
  311.         fputs(infname, stderr);
  312.         fputc('\n', stderr);
  313.         exit(RETURN_ERROR);
  314.     }
  315. }
  316.  
  317. /*
  318.  *  CREATE THE .AFM FILE
  319.  */
  320. VOID  openafm(VOID)
  321. {
  322.     UBYTE *cp;
  323.  
  324.     /* ADD .AFM IF THERE IS NONE */
  325.     if (!*outfname)
  326.     {   strcpy(outfname, infname);
  327.         cp = outfname+strlen(outfname)-1;
  328.         while (cp >= outfname && *cp != '.' && *cp != '/' && *cp != ':')
  329.            cp--;
  330.         if (*cp == '.')
  331.             *cp = 0;
  332.         strcat(outfname, ".afm");
  333.     }
  334.  
  335.     /* OPEN THE FILE */
  336.     outf = fopen(outfname, "w");
  337.     if (!outf)
  338.     {   strcpy(mmsg, "Unable to open output file \"");
  339.         strcat(mmsg, outfname);
  340.         strcat(mmsg, "\"");
  341.         perror(mmsg);
  342.         exit(RETURN_ERROR);
  343.     }
  344. }
  345.  
  346. /*
  347.  *  PUT OUT THE HEADER OF THE .AFM FILE
  348.  */
  349. VOID  putheader(VOID)
  350. {
  351.     UBYTE * cp;
  352.  
  353.     fputs("StartFontMetrics 2.0\n", outf);
  354.     if (pfm.copyright[0])
  355.     {   fputs("Comment ", outf);
  356.         fputs(pfm.copyright, outf);
  357.         fputc('\n', outf);
  358.     }
  359.     fputs("FontName ", outf);
  360.     fputs(buffer+pfm.fontname, outf);
  361.     fputs("\nEncodingScheme ", outf);
  362.     if (pfm.charset)
  363.         fputs("FontSpecific\n", outf);
  364.     else
  365.         fputs("AdobeStandardEncoding\n", outf);
  366.  
  367.     /*
  368.      * The .pfm is missing full name, so construct from font name by
  369.      * changing the hyphen to a space.  This actually works in a lot
  370.      * of cases.
  371.      */
  372.     fputs("FullName ", outf);
  373.     cp = buffer+pfm.fontname;
  374.     while (*cp)
  375.     {   if (*cp == '-')
  376.             *cp = ' ';
  377.         fputc(*cp, outf);
  378.         cp++;
  379.     }
  380.     if (pfm.face)
  381.     {   fputs("\nFamilyName ", outf);
  382.         fputs(buffer+pfm.face, outf);
  383.     }
  384.  
  385.     fputs("\nWeight ", outf);
  386.     if (pfm.weight > 475)
  387.         fputs("Bold", outf);
  388.     else if (pfm.weight < 325 && pfm.weight)
  389.         fputs("Light", outf);
  390.     else
  391.         fputs("Medium", outf);
  392.  
  393.     /*
  394.      *  The mono flag in the pfm actually indicates whether there is a
  395.      *  table of font widths, not if they are all the same.
  396.      */
  397.     fputs("\nIsFixedPitch ", outf);
  398.     if (!(pfm.kind & 1)                   /* FLAG FOR MONO */
  399.     || pfm.avgwidth == pfm.maxwidth)      /* AVG WIDTH = MAX WIDTH */
  400.     {   fputs("true", outf);
  401.         isMono = 1;
  402.     }
  403.     else
  404.     {   fputs("false", outf);
  405.         isMono = 0;
  406.     }
  407.  
  408.     /*
  409.      * The font bounding box is lost, but try to reconstruct it.
  410.      * Much of this is just guess work.  The bounding box is required in
  411.      * the .afm, but is not used by the PM font installer.
  412.      */
  413.  
  414.     /* UNPACK RECORD INTO PSX STRUCT */
  415.     memcpy(&psx, buffer+pfm.psext, sizeof(psx));
  416.     revbyt((UBYTE *)&psx.capheight, sizeof(psx.capheight));
  417.     revbyt((UBYTE *)&psx.xheight,   sizeof(psx.xheight));
  418.     revbyt((UBYTE *)&psx.ascender,  sizeof(psx.ascender));
  419.     revbyt((UBYTE *)&psx.descender, sizeof(psx.descender));
  420.  
  421.     fputs("\nFontBBox", outf);
  422.     if (isMono)                   /* JUST GUESS AT LEFT BOUNDS */
  423.         outval(-20);
  424.     else
  425.         outval(-100);
  426.  
  427.     /*
  428.      * Some .PFMs give the descender as a positive value,
  429.      * and others give it as negative...
  430.      */
  431.     outval(-(abs(psx.descender)+5));
  432.  
  433.     outval(pfm.maxwidth+10);
  434.     outval(pfm.ascent+5);
  435.  
  436.     /*
  437.      * GIVE OTHER METRICS THAT WERE KEPT
  438.      */
  439.     fputs("\nCapHeight", outf);
  440.     outval(psx.capheight);
  441.     fputs("\nXHeight", outf);
  442.     outval(psx.xheight);
  443.     fputs("\nDescender", outf);
  444.     outval(-abs(psx.descender));
  445.     fputs("\nAscender", outf);
  446.     outval(psx.ascender);
  447.     fputc('\n', outf);
  448. }
  449.  
  450. /*
  451.  *  Put out the character tables.  According to the .afm spec, the
  452.  *  characters must be put out sorted in encoding order.
  453.  *
  454.  *  Most Windows .pfm files have the characters in the range 20-ff in
  455.  *  the Windows code page (819 + quotes).
  456.  */
  457. VOID  putchartab(VOID)
  458. {
  459.     int     count, i, j;
  460.     UWORD   spwidth;
  461.     UWORD * ctab, chartab[256];
  462.     UBYTE   back[256];
  463.  
  464.  
  465.     count = pfm.lastchar - pfm.firstchar + 1;
  466.  
  467.     /* UNPACK CHARACTER TABLE INTO CHARTAB */
  468.     for (i = 0; i < count; i++)
  469.     {   memcpy(&chartab[i], buffer + pfm.chartab + i*sizeof(UWORD),
  470.             sizeof(UWORD));
  471.         revbyt((UBYTE *)(&chartab[i]), sizeof(UWORD));
  472.     }
  473.  
  474.     /*
  475.      * Compute the count by getting rid of non-existant chars.  This
  476.      * is complicated by the fact that Windows encodes the .pfm file
  477.      * with a space metric for non-existant chars.
  478.      */
  479.     memset(back, 0, 256);
  480.     spwidth = 0;
  481.  
  482.     /* COMPUTE WIDTH OF SPACE */
  483.     ctab = chartab;
  484.     if (pfm.firstchar <= ' ' && pfm.lastchar >= ' ')
  485.         spwidth = ctab[' ' - pfm.firstchar];
  486.  
  487.     /*
  488.      *  Loop thru the chars, deleting those that we presume
  489.      *  do not really exist.
  490.      */
  491.     if (!pfm.charset)
  492.     {   for (i = pfm.firstchar; i <= (int)pfm.lastchar; i++)
  493.         {   if (Win2PSStd[i])
  494.                 back[Win2PSStd[i]] = (UBYTE)i;
  495.             else
  496.             {   if (!allflag)
  497.                 {   if (*ctab == spwidth)
  498.                     {
  499.                         /* DEFAULT WIDTH */
  500.                         if (!(WinClass[i] & 1))
  501.                         {   *ctab = 0;
  502.                             count--;
  503.                         }
  504.                     }
  505.                     else
  506.                     {
  507.                         /* NOT DEFAULT WIDTH */
  508.                         if (!WinClass[i])
  509.                         {   *ctab = 0;
  510.                             count--;
  511.                         }
  512.                     }
  513.                 }
  514.             }
  515.             ctab++;
  516.         }
  517.     }
  518.  
  519.     /* PUT OUT THE HEADER */
  520.     fputs("StartCharMetrics", outf);
  521.     outval(count);
  522.     fputc('\n', outf);
  523.  
  524.     /*
  525.      * If the charset is not the Windows standard, just put out
  526.      * unnamed entries.
  527.      */
  528.     ctab = chartab;
  529.     if (pfm.charset)
  530.     {   for (i = pfm.firstchar; i <= (int)pfm.lastchar; i++)
  531.         {   if (*ctab)
  532.                 outchar(i, *ctab, NULL);
  533.             ctab++;
  534.         }
  535.     }
  536.     else
  537.     {   for (i = 0; i < 256; i++)
  538.         {   j = back[i];
  539.             if (j)
  540.             {   outchar(i, ctab[j - pfm.firstchar], WinChars[j]);
  541.                 ctab[j - pfm.firstchar] = 0;
  542.             }
  543.         }
  544.         /* PUT OUT ALL NON-ENCODED CHARS */
  545.         for (i = pfm.firstchar; i <= (int)pfm.lastchar; i++)
  546.         {   if (*ctab)
  547.                 outchar(-1, *ctab, WinChars[i]);
  548.             ctab++;
  549.         }
  550.     }
  551.  
  552.     /* PUT OUT THE TRAILER */
  553.     fputs("EndCharMetrics\n", outf);
  554. }
  555.  
  556. /*
  557.  *  Output a character entry
  558.  */
  559. VOID  outchar(code, width, name)
  560. int           code;
  561. UWORD               width;
  562. UBYTE                     *name;
  563. {
  564.     fputs("C ", outf);
  565.     outval(code);
  566.     fputs(" ; WX ", outf);
  567.     outval(width);
  568.     if (name)
  569.     {   fputs(" ; N ", outf);
  570.         fputs(name, outf);
  571.     }
  572.     fputs(" ;\n", outf);
  573. }
  574.  
  575. /*
  576.  *  PUT OUT THE KERNING TABLES
  577.  */
  578. VOID  putkerntab(kerntab, kerncnt)
  579. KERN            *kerntab;
  580. UWORD                     kerncnt;
  581. {
  582.     int count, i;
  583.     KERN  k, *kp;
  584.  
  585.     /* COUNT NON-ZERO KERN PAIRS */
  586.     count = kerncnt;
  587.     kp = kerntab;
  588.     for (i = 0; i < kerncnt; i++)
  589.     {   memcpy(&k, kp, 4);
  590.         if (!k.kern)
  591.             count--;
  592.         kp++;
  593.     }
  594.  
  595.     /* PUT OUT HEADER */
  596.     fputs("StartKernData\nStartKernPairs", outf);
  597.     outval(count);
  598.     fputc('\n', outf);
  599.  
  600.     /* PUT OUT EACH NON-ZERO PAIR */
  601.     kp = kerntab;
  602.     while (kerncnt)
  603.     {   memcpy(&k, kp, 4);
  604.         if (k.kern)
  605.         {   revbyt((UBYTE *)&k.kern, sizeof(k.kern));
  606.             fputs("KPX ", outf);
  607.             fputs(WinChars[k.first], outf);
  608.             fputc(' ', outf);
  609.             fputs(WinChars[k.second], outf);
  610.             outval(k.kern);
  611.             fputc('\n', outf);
  612.         }
  613.         kp++;
  614.         kerncnt--;
  615.     }
  616.  
  617.     /* PUT OUT TRAILER */
  618.     fputs("EndKernPairs\nEndKernData\n", outf);
  619. }
  620.  
  621. /*
  622.  *  PUT OUT THE TRAILER OF THE .AFM FILE
  623.  */
  624. VOID  puttrailer(VOID)
  625. {
  626.     fputs("EndFontMetrics\n", outf);
  627. }
  628.  
  629. /*
  630.  *  OUTPUT A DECIMAL VALUE
  631.  */
  632. VOID outval(v)
  633. int         v;
  634. {
  635.     UBYTE chx[16];
  636.  
  637.     /* LATTICE EQUIV. OF itoa() */
  638.     stci_d(chx, v);
  639.  
  640.     fputc(' ', outf);
  641.     fputs(chx, outf);
  642. }
  643.  
  644. /*
  645.  *  REVERSE THE BYTES IN A BINARY VALUE
  646.  */
  647. VOID revbyt    (tp,len)
  648. REGISTER UBYTE *tp;
  649. int                len;
  650. {
  651.     REGISTER UBYTE *hp;
  652.     UBYTE ch;
  653.  
  654.     hp = tp + len - 1;
  655.     while (tp < hp)
  656.     {   ch    = *tp;
  657.         *tp++ = *hp;
  658.         *hp-- = ch;
  659.     }
  660. }
  661.