home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 517a.lha / FontManipulatorForDtp_v2 / source / mkmetric / mkmetric.c < prev    next >
C/C++ Source or Header  |  1991-06-09  |  25KB  |  991 lines

  1. /* Metric file builder for PPage etc.  File "mkmetric.c".
  2.  * (C) Adrian Aylward 1991
  3.  *
  4.  * You may freely copy, use, and modify this file.
  5.  *
  6.  * This program prints builds a font metric (.metric) file in the format
  7.  * used by Professional Page.  Its input is one or more Adobe font metric
  8.  * (.afm) files.
  9.  *
  10.  * The program was tested using Lattice C V5.05.  It has various Lattice
  11.  * dependencies.
  12.  *
  13.  * This is version 1.1.
  14.  */
  15.  
  16. # include <dos.h>
  17. # include <exec/exec.h>
  18. # include <proto/dos.h>
  19. # include <proto/exec.h>
  20. # include <string.h>
  21. # include <setjmp.h>
  22. # include <stdio.h>
  23.  
  24. /* Metric file format */
  25.  
  26. struct mfile_header
  27. {   int mf_sect[5];
  28. };
  29.  
  30. struct msect_header
  31. {   char ms_fontname[40];
  32.     char ms_filler1[26];
  33.     int ms_widthtable;
  34.     int ms_kerntable;
  35.     char ms_filler2[6];
  36.     char ms_fixedpitch;           /* 0 = fixed, 1 = variable */
  37.     char ms_encoding;             /* 0 = font, 1 = standard */
  38.     short ms_fontbbox[4];
  39.     short ms_underlineposition;
  40.     short ms_underlinethickness;
  41.     short ms_capheight;
  42.     short ms_xheight;
  43.     short ms_ascender;
  44.     short ms_descender;
  45.     short ms_stype;
  46. };
  47.  
  48. struct mkern_entry
  49. {   short mk_value;
  50.     short mk_code;
  51. };
  52.  
  53. /* External data (initialised to zero) */
  54.  
  55. char *argmetricfile, *argafmfiles;
  56. char *argencodingfile;
  57. int optfontencoding, optsetfontencoding;
  58.  
  59. int lochar, hichar;
  60.  
  61. BPTR newfh;
  62.  
  63. # define memsize 10000
  64.  
  65. char *membeg[100], *memptr;
  66. int memsegs, memfree;
  67.  
  68.  
  69. # define filesize 100000
  70.  
  71. char *filemem;
  72. int filelen;
  73.  
  74. struct mfile_header *mfhdr;
  75. struct msect_header *mshdr;
  76.  
  77. int sectno, sectbeg;
  78.  
  79. short *widthbeg;
  80.  
  81. int kernflag;
  82. struct mkern_entry *kernbeg;
  83.  
  84. char currentfile[100];
  85. FILE *currentfptr;
  86.  
  87. # define NOURCH   (EOF - 1)
  88.  
  89. int lineno, urch;
  90. int scanmode;
  91.  
  92. int retcode;
  93. jmp_buf errjmp;
  94.  
  95. # define typeeof     0
  96. # define typeeol     1
  97. # define typesemi    2
  98. # define typepercent 3
  99. # define typename    4
  100. # define typeint     5
  101.  
  102. int tokentype, tokenival;
  103.  
  104. char namebuf[256];
  105.  
  106. char charname[256], charpair[256];
  107.  
  108. char *charstr;
  109.  
  110. int charcode, charwidth, charkern;
  111. int fontwidth;
  112.  
  113. int kernsize;
  114. short *kerntable[256];
  115.  
  116. /* Encoding vector, initially Adobe StandardEncoding */
  117.  
  118. char *encoding[256] =
  119. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  120.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  121.   "space",         "exclam",        "quotedbl",      "numbersign", /* 20 */
  122.   "dollar",        "percent",       "ampersand",     "quoteright",
  123.   "parenleft",     "parenright",    "asterisk",      "plus",
  124.   "comma",         "hyphen",        "period",        "slash",
  125.   "zero",          "one",           "two",           "three",      /* 30 */
  126.   "four",          "five",          "six",           "seven",
  127.   "eight",         "nine",          "colon",         "semicolon",
  128.   "less",          "equal",         "greater",       "question",
  129.   "at",            "A",             "B",             "C",          /* 40 */
  130.   "D",             "E",             "F",             "G",
  131.   "H",             "I",             "J",             "K",
  132.   "L",             "M",             "N",             "O",
  133.   "P",             "Q",             "R",             "S",          /* 50 */
  134.   "T",             "U",             "V",             "W",
  135.   "X",             "Y",             "Z",             "bracketleft",
  136.   "backslash",     "bracketright",  "asciicircum",   "underscore",
  137.   "quoteleft",     "a",             "b",             "c",          /* 60 */
  138.   "d",             "e",             "f",             "g",
  139.   "h",             "i",             "j",             "k",
  140.   "l",             "m",             "n",             "o",
  141.   "p",             "q",             "r",             "s",          /* 70 */
  142.   "t",             "u",             "v",             "w",
  143.   "x",             "y",             "z",             "braceleft",
  144.   "bar",           "braceright",    "asciitilde",    0,
  145.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  146.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  147.   0,               "exclamdown",    "cent",          "sterling",   /* A0 */
  148.   "fraction",      "yen",           "florin",        "section",
  149.   "currency",      "quotesingle",   "quotedblleft",  "guillemotleft",
  150.   "guilsinglleft", "guilsinglright","fi",            "fl",
  151.   0,               "endash",        "dagger",        "daggerdbl",  /* B0 */
  152.   "periodcentered",0,               "paragraph",     "bullet",
  153.   "quotesinglbase","quotedblbase",  "quotedblright", "guillemotright",
  154.   "ellipsis",      "perthousand",   0,               "questiondown",
  155.   0,               "grave",         "acute",         "circumflex", /* C0 */
  156.   "tilde",         "macron",        "breve",         "dotaccent",
  157.   "dieresis",      0,               "ring",          "cedilla",
  158.   0,               "hungarumlaut",  "ogonek",        "caron",
  159.   "emdash",        0,               0,               0,            /* D0 */
  160.   0,               0,               0,               0,
  161.   0,               0,               0,               0,
  162.   0,               0,               0,               0,
  163.   0,               "AE",            0,               "ordfeminine",/* E0 */
  164.   0,               0,               0,               0,
  165.   "Lslash",        "Oslash",        "OE",            "ordmasculine",
  166.   0,               0,               0,               0,
  167.   0,               "ae",            0,               0,            /* F0 */
  168.   0,               "dotlessi",      0,               0,
  169.   "lslash",        "oslash",        "oe",            "germandbls",
  170.   0,               0,               0,               0
  171. };
  172.  
  173. /* Routines */
  174.  
  175. extern int  strtoint(char **sp, int *ip);
  176. extern void readencoding(void);
  177. extern void convertafm(void);
  178. extern int  mvalue(int val);
  179. extern void rdkey(void);
  180. extern void rdname(void);
  181. extern void rdbool(void);
  182. extern void rdint(void);
  183. extern void rdnumb(void);
  184. extern void rdstring(void);
  185. extern void rdtoken(void);
  186. extern void checksemi(void);
  187. extern void checkeol(void);
  188. extern void skipsemi(void);
  189. extern void skipeol(void);
  190. extern void skipspace(void);
  191. extern int  rdch(void);
  192. extern void unrdch(int ch);
  193. extern void errsyntax(char *f);
  194. extern void errfilesize(void);
  195. extern void errmemory(void);
  196. extern void makekern(int code, int pair, int kern);
  197. extern int  buildkern(int maxlen);
  198. extern char *makestring(char *str);
  199. extern void *allocmem(int size);
  200. extern void freeall(void);
  201. extern void stub(void);
  202. extern void chkabort(void);
  203.  
  204. /* Main program */
  205.  
  206. void main(int argc, char **argv)
  207. {   char *s, *t;
  208.     int *ip, i, ch;
  209.  
  210.     /* Parse arguments.  No workbench startup */
  211.  
  212.     lochar = 32;
  213.     hichar = 255;
  214.  
  215.     if (argc == 0) goto tidyexit;
  216.     argv++;
  217.     argc--;
  218.     if (argc == 0 || (argc == 1 && strcmp(*argv, "?") == 0)) goto query;
  219.  
  220.     while (argc)
  221.     {   s = *argv;
  222.         if (*s != '-') break;
  223.         argv++;
  224.         argc--;
  225.         if (strcmp(s, "--") == 0) break;
  226.         s++;
  227.         for (;;)
  228.         {   ch = *s++;
  229.             if (ch == 0) break;
  230.             switch (ch)
  231.             {   case 'E': case 'e':
  232.                     if (argc == 0) goto badargs;
  233.                     argencodingfile = *argv++;
  234.                     argc--;
  235.                     continue;
  236.  
  237.                 case 'F': case 'f':
  238.                     optfontencoding = 1;
  239.                     continue;
  240.  
  241.                 case 'S': case 's':
  242.                     optsetfontencoding = 1;
  243.                     continue;
  244.  
  245.                 case 'L': case 'l':
  246.                     ip = &lochar;
  247.                     break;
  248.  
  249.                 case 'H': case 'h':
  250.                     ip = &hichar;
  251.                     break;
  252.  
  253.                 default:
  254.                     fprintf(stderr, "mkmetric: unknown option \"-%c\"", ch);
  255.                     goto badusage;
  256.             }
  257.             if (!strtoint(&s, ip)) goto badargs;
  258.         }
  259.  
  260.         if (*s == '-' && *(s + 1) == 0) break;
  261.     }
  262.  
  263.     if (lochar > hichar || hichar > 255)
  264.     {   fprintf(stderr, "mkmetric: LoChar/HiChar out of range "
  265.                                 "(0 <= Lo <= Hi <= 255)\n");
  266.         goto errorexit;
  267.     }
  268.  
  269.     if (argc != 2) goto badargs;
  270.     argmetricfile = argv[0];
  271.     argafmfiles = argv[1];
  272.  
  273.     if (argencodingfile == NULL) argencodingfile = "PSFonts:encoding.ps";
  274.  
  275.     /* Read the encoding file */
  276.  
  277.     if (optfontencoding == 0)
  278.     {   strncpy(currentfile, argencodingfile, 99);
  279.         currentfile[99] = 0;
  280.         currentfptr = fopen(argencodingfile, "r");
  281.         if (currentfptr == NULL)
  282.         {   fprintf(stderr, "mkmetric: can't open encoding file %s\n",
  283.                     argencodingfile);
  284.             goto errorexit;
  285.         }
  286.         readencoding();
  287.         if (retcode != 0) goto errorexit;
  288.         fclose(currentfptr);
  289.         currentfptr = NULL;
  290.     }
  291.     else
  292.         memset((char *) encoding, 0, sizeof (encoding));
  293.  
  294.     /* Allocate the metric file memory */
  295.  
  296.     filemem = AllocMem(filesize, MEMF_CLEAR);
  297.     if (filemem == NULL)
  298.     {   fprintf(stderr, "mkbmap: can't get metrci file memory\n");
  299.         goto errorexit;
  300.     }
  301.     mfhdr = (void *) filemem;
  302.     filelen = sizeof (struct mfile_header);
  303.  
  304.     /* Loop to process all the AFM files */
  305.  
  306.     sectno = 0;
  307.     s = argafmfiles;
  308.     for (;;)
  309.     {   t = s;
  310.         while (*t != ',' && *t != 0) t++;
  311.         i = t - s;
  312.         if (i >= 100)
  313.         {   fprintf(stderr, "mkmetric: afm file name too long\n");
  314.             goto errorexit;
  315.         }
  316.         if (i == 0)
  317.         {   if (sectno == 0)
  318.             {   fprintf(stderr,
  319.                         "mkmetric: plain version afm file name missing\n");
  320.                 goto errorexit;
  321.             }
  322.         }
  323.         else
  324.         {   memcpy(currentfile, s, i);
  325.             currentfile[i] = 0;
  326.             currentfptr = fopen(currentfile, "r");
  327.             if (currentfptr == NULL)
  328.             {   fprintf(stderr,
  329.                         "mkmetric: can't open afm file %s\n", currentfile);
  330.                 goto errorexit;
  331.             }
  332.             mfhdr->mf_sect[sectno] = filelen;
  333.             convertafm();
  334.             if (retcode != 0) goto errorexit;
  335.             fclose(currentfptr);
  336.             currentfptr = NULL;
  337.         }
  338.         sectno++;
  339.         if (*t == 0) break;
  340.         s = t + 1;
  341.     }
  342.     mfhdr->mf_sect[4] = filelen;
  343.  
  344.     /* All done. Write out the file an exit */
  345.  
  346.     newfh = Open(argmetricfile, MODE_NEWFILE);
  347.     if (newfh == NULL)
  348.     {   fprintf(stderr, "mkmetric: can't open metric file %s\n",
  349.                 argmetricfile);
  350.         goto errorexit;
  351.     }
  352.     i = Write(newfh, (UBYTE *) filemem, filelen);
  353.     Close(newfh);
  354.     if (i == -1)
  355.     {   fprintf(stderr, "mkmetric: error writing metric file %s\n",
  356.                 argmetricfile);
  357.         goto errorexit;
  358.     }
  359.     goto tidyexit;
  360.  
  361.     /* Argument errors and usage query */
  362.  
  363. query:
  364.     fprintf(stderr, "Metric file builder.  MkMetric version 1.1\n"
  365.                     "Makes PPage .metric files from Adobe .afm files\n"
  366.                     "\n"
  367.                     "  Usage:\n"
  368.                     "\n"
  369.                     "    mkmetric -options metricfile "
  370.                                 "plain.afm,bold..,italic..,bolditalic..\n"
  371.                     "\n"
  372.                     "      -e encodingfile  Encoding file name\n"
  373.                     "      -f               Font specific encoding\n"
  374.                     "      -s               Set font specific encoding\n"
  375.                     "      -n               No character names\n");
  376.     fprintf(stderr, "      -lnnn            LoChar\n"
  377.                     "      -hnnn            Hichar\n"
  378.                     "\n"
  379.                     "  For example:\n"
  380.                     "\n"
  381.                     "    mkmetric fonts:CooperBlack.metric "
  382.                                 "CooperBlack.afm,,CooperBlack-Italic.afm\n");
  383.     goto tidyexit;
  384.  
  385. badargs:
  386.     fprintf(stderr, "mkmetric: arguments bad, or value missing");
  387. badusage:
  388.     retcode = 20;
  389.     fprintf(stderr, ".  Usage:\n"
  390.                     "    mkmetric -options metricfile "
  391.                                 "plain.afm,bold..,italic..,bolditalic..\n");
  392.     goto tidyexit;
  393.  
  394.     /* Tidy up and exit */
  395.  
  396. broken:
  397.     fprintf(stderr, "mkmetric: *** Break\n");
  398.     retcode = 10;
  399.     goto tidyexit;
  400.  
  401. errorexit:
  402.     retcode = 20;
  403.  
  404. tidyexit:
  405.     if (currentfptr) fclose(currentfptr);
  406.     currentfptr = NULL;
  407.     if (filemem) FreeMem(filemem, filesize);
  408.     freeall();
  409.     exit(retcode);
  410. }
  411.  
  412. /* String to integer conversion; digits only, with error check */
  413.  
  414. int strtoint(char **sp, int *ip)
  415. {   char *s = *sp;
  416.     int i = 0;
  417.     int ch;
  418.     for (;;)
  419.     {   ch = *s;
  420.         if (ch < '0' || ch > '9') break;
  421.         i = i * 10 + (ch - '0');
  422.         s++;
  423.     }
  424.     if (s == *sp)
  425.         return 0;
  426.     else
  427.     {   *sp = s;
  428.         *ip = i;
  429.         return 1;
  430.     }
  431. }
  432.  
  433. /* Read the encoding file */
  434.  
  435. void readencoding(void)
  436. {   lineno = 1;
  437.     urch = NOURCH;
  438.     scanmode = 0;
  439.  
  440.     retcode = setjmp(errjmp);
  441.     if (retcode != 0) return;
  442.  
  443.     for (;;)
  444.     {   rdtoken();
  445.         if (tokentype == typeeof) break;
  446.         if (tokentype == typeeol) continue;
  447.         if (tokentype != typeint) errsyntax("integer expected");
  448.         charcode = tokenival;
  449.         rdtoken();
  450.         if (tokentype != typename) errsyntax("name expected");
  451.         if (namebuf[0] == '/')
  452.            charstr = makestring(&namebuf[1]);
  453.         else
  454.            charstr = makestring(&namebuf[0]);
  455.         rdtoken();
  456.         if (tokentype != typeeol) errsyntax("end of line expected");
  457.         if (charcode < 0 || charcode > 255)
  458.             errsyntax("character code out of range");
  459.         encoding[charcode] = charstr;
  460.     }
  461. }
  462.  
  463. /* Convert a single AFM file */
  464.  
  465. void convertafm(void)
  466. {   int i, j;
  467.  
  468.     sectbeg = filelen;
  469.     mshdr = (void *) (filemem + filelen);
  470.     filelen += sizeof (struct msect_header);
  471.     if (filelen > filesize) errfilesize();
  472.     mshdr->ms_fixedpitch = 1;
  473.     mshdr->ms_encoding = (optfontencoding | optsetfontencoding) ? 0 : 1;
  474.     mshdr->ms_stype = sectno + 1;
  475.     mshdr->ms_widthtable = filelen - sectbeg;
  476.     widthbeg = (void *) (filemem + filelen);
  477.     filelen += sizeof (short) * 256;
  478.     if (filelen > filesize) errfilesize();
  479.  
  480.     lineno = 1;
  481.     urch = NOURCH;
  482.     scanmode = 1;
  483.  
  484.     retcode = setjmp(errjmp);
  485.     if (retcode != 0) return;
  486.  
  487.     kernflag = 0;
  488.     for (i = lochar; i <= hichar; i++) kerntable[i] = NULL;
  489.  
  490.     rdkey();
  491.     if (strcmp(namebuf, "StartFontMetrics") != 0)
  492.         errsyntax("StartFontMetrics expected\n");
  493.     skipeol();
  494.  
  495. rdl:
  496.     rdkey();
  497.     if (strcmp(namebuf, "EndFontMetrics") == 0)
  498.     {   skipeol();
  499.         goto eof;
  500.     }
  501.     if (strcmp(namebuf, "FontName") == 0)
  502.     {   rdstring();
  503.         strncpy(mshdr->ms_fontname, namebuf, 40);
  504.         goto rdl;
  505.     }
  506.     if (strcmp(namebuf, "FontBBox") == 0)
  507.     {   for (i = 0 ; i < 4; i++)
  508.         {   rdint();
  509.             mshdr->ms_fontbbox[i] = mvalue(tokenival);
  510.         }
  511.         checkeol();
  512.         goto rdl;
  513.     }
  514.     if (strcmp(namebuf, "CapHeight") == 0)
  515.     {   rdnumb();
  516.         mshdr->ms_capheight = mvalue(tokenival);
  517.         checkeol();
  518.         goto rdl;
  519.     }
  520.     if (strcmp(namebuf, "XHeight") == 0)
  521.     {   rdnumb();
  522.         mshdr->ms_xheight = mvalue(tokenival);
  523.         checkeol();
  524.         goto rdl;
  525.     }
  526.     if (strcmp(namebuf, "Ascender") == 0)
  527.     {   rdnumb();
  528.         mshdr->ms_ascender = mvalue(tokenival);
  529.         checkeol();
  530.         goto rdl;
  531.     }
  532.     if (strcmp(namebuf, "Descender") == 0)
  533.     {   rdnumb();
  534.         mshdr->ms_descender = mvalue(tokenival);
  535.         checkeol();
  536.         goto rdl;
  537.     }
  538.     if (strcmp(namebuf, "UnderlinePosition") == 0)
  539.     {   rdnumb();
  540.         mshdr->ms_underlineposition = mvalue(tokenival);
  541.         checkeol();
  542.         goto rdl;
  543.     }
  544.     if (strcmp(namebuf, "UnderlineThickness") == 0)
  545.     {   rdnumb();
  546.         mshdr->ms_underlinethickness = mvalue(tokenival);
  547.         checkeol();
  548.         goto rdl;
  549.     }
  550.     if (strcmp(namebuf, "CharWidth") == 0)
  551.     {   rdnumb();
  552.         fontwidth = mvalue(tokenival);
  553.         rdnumb();
  554.         checkeol();
  555.         goto rdl;
  556.     }
  557.     if (strcmp(namebuf, "IsFixedPitch") == 0)
  558.     {   rdbool();
  559.         mshdr->ms_fixedpitch = tokenival ? 0 : 1;
  560.         checkeol();
  561.         goto rdl;
  562.     }
  563.  
  564.     if (strcmp(namebuf, "C") == 0)
  565.     {   charcode = -1;
  566.         charname[0] = 0;
  567.         charwidth = fontwidth;
  568.         rdint();
  569.         charcode = tokenival;
  570.         if (charcode > 255) errsyntax("character code out of range");
  571.         checksemi();
  572.         for (;;)
  573.         {   rdtoken();
  574.             if (tokentype == typeeol) break;
  575.             if (tokentype != typename) errsyntax("key expected");
  576.             if      (strcmp(namebuf, "N") == 0)
  577.             {   rdname();
  578.                 strcpy(charname, namebuf);
  579.                 checksemi();
  580.             }
  581.             else if (strcmp(namebuf, "WX") == 0)
  582.             {   rdnumb();
  583.                 charwidth = mvalue(tokenival);
  584.                 checksemi();
  585.             }
  586.             else
  587.                 skipsemi();
  588.         }
  589.         if (optfontencoding == 0)
  590.         {   if (charname[0] == 0) errsyntax("character name missing");
  591.             for (i = lochar; i <= hichar; i++)
  592.                 if (encoding[i] != NULL &&
  593.                         strcmp(encoding[i], charname) == 0)
  594.                     widthbeg[i] = charwidth;
  595.         }
  596.         else
  597.             if (charcode >= lochar && charcode <= hichar)
  598.             {   if (charname[0] != 0)
  599.                     encoding[charcode] = makestring(charname);
  600.                 widthbeg[charcode] = charwidth;
  601.             }
  602.         goto rdl;
  603.     }
  604.  
  605.     if (strcmp(namebuf, "KPX") == 0)
  606.     {   rdname();
  607.         strcpy(charname, namebuf);
  608.         rdname();
  609.         strcpy(charpair, namebuf);
  610.         rdnumb();
  611.         charkern = mvalue(tokenival);
  612.         checkeol();
  613.         if (charkern != 0)
  614.             for (i = lochar; i <= hichar; i++)
  615.                 if (encoding[i] != NULL &&
  616.                         strcmp(encoding[i], charname) == 0)
  617.                     for (j = lochar; j <= hichar; j++)
  618.                         if (encoding[j] != NULL &&
  619.                                 strcmp(encoding[j], charname) == 0)
  620.                         {   kernflag = 1;
  621.                             makekern(i, j, charkern);
  622.                         }
  623.         goto rdl;
  624.     }
  625.  
  626.     skipeol();
  627.     goto rdl;
  628.  
  629.     /* End of file.  Build the kerning (sparse) array */
  630. eof:
  631.     if (kernflag)
  632.     {   mshdr->ms_kerntable = filelen - sectbeg;
  633.         kernbeg = (void *) (filemem + filelen);
  634.         filelen += buildkern(filesize - filelen);
  635.     }
  636. }
  637.  
  638. /* Scale a character coordinate value for the .metric file */
  639.  
  640. int  mvalue(int val)
  641. {   return (val * 1024) / 1000;
  642. }
  643.  
  644. /* Read key from beginning of line */
  645.  
  646. void rdkey(void)
  647. {
  648. rdl:
  649.     rdtoken();
  650.     if (tokentype == typeeol) goto rdl;
  651.     if (tokentype != typename) errsyntax("key name expected");
  652.     if (strcmp(namebuf, "Comment") == 0)
  653.     {   skipeol();
  654.         goto rdl;
  655.     }
  656. }
  657.  
  658. /* Read a name */
  659.  
  660. void rdname(void)
  661. {   rdtoken();
  662.     if (tokentype != typename) errsyntax("name expected");
  663. }
  664.  
  665. /* Read a boolean */
  666.  
  667. void rdbool(void)
  668. {   rdtoken();
  669.     if      (tokentype == typename && strcmp(namebuf, "true") == 0)
  670.         tokenival = 1;
  671.     else if (tokentype == typename && strcmp(namebuf, "false") == 0)
  672.         tokenival = 0;
  673.     else
  674.         errsyntax("boolean expected");
  675. }
  676.  
  677. /* Read an integer */
  678.  
  679. void rdint(void)
  680. {   rdtoken();
  681.     if (tokentype != typeint) errsyntax("integer expected");
  682. }
  683.  
  684. /* Read a number (no support for reals) */
  685.  
  686. void rdnumb(void)
  687. {   rdtoken();
  688.     if (tokentype != typeint) errsyntax("number expected");
  689. }
  690.  
  691. /* Read a string */
  692.  
  693. void rdstring(void)
  694. {   int i, ch;
  695.     skipspace();
  696.     i = 0;
  697.     for (;;)
  698.     {   ch = rdch();
  699.         if (ch == EOF || ch == '\n') break;
  700.         if (i >= 255) errsyntax("string too long");
  701.         namebuf[i++] = ch;
  702.     }
  703.     namebuf[i] = 0;
  704.     unrdch(ch);
  705. }
  706.  
  707. /* Read the next token */
  708.  
  709. void rdtoken(void)
  710. {   int val, i, j, ch;
  711.     skipspace();
  712.     i = 0;
  713.     for (;;)
  714.     {   ch = rdch();
  715.         if (ch == EOF)
  716.         {   if (i == 0)
  717.             {   tokentype = typeeof;
  718.                 return;
  719.             }
  720.             else
  721.                 break;
  722.         }
  723.         if (scanmode == 0)
  724.         {   if (ch == '%')
  725.             {   if (i == 0)
  726.                 {   skipeol();
  727.                     tokentype = typeeol;
  728.                     return;
  729.                 }
  730.                 else
  731.                     break;
  732.             }
  733.         }
  734.         else
  735.         {   if (ch == ';')
  736.             {   if (i == 0)
  737.                 {   tokentype = typesemi;
  738.                     return;
  739.                 }
  740.                 else
  741.                     break;
  742.             }
  743.         }
  744.         if (ch == '\n')
  745.         {   if (i == 0)
  746.             {   tokentype = typeeol;
  747.                 return;
  748.             }
  749.             else
  750.                 break;
  751.         }
  752.         if (ch == ' ' || ch == '\t') break;
  753.         if (i >= 255) errsyntax("token too long");
  754.         namebuf[i++] = ch;
  755.     }
  756.     namebuf[i] = 0;
  757.     unrdch(ch);
  758.     tokentype = typename;
  759.     {   j = 0;
  760.         if (namebuf[0] == '-')
  761.         {   j++;
  762.             if (i <= j) return;
  763.         }
  764.         val = 0;
  765.         while (j < i)
  766.         {   ch = namebuf[j];
  767.             if (ch < '0' || ch > '9') return;
  768.             val = val * 10 + (ch - '0');
  769.             j++;
  770.         }
  771.         if (namebuf[0] == '-') val = -val;
  772.         tokentype = typeint;
  773.         tokenival = val;
  774.     }
  775. }
  776.  
  777. /* Check for semicolon */
  778.  
  779. void checksemi(void)
  780. {   rdtoken();
  781.     if (tokentype != typesemi) errsyntax("semicolon expected");
  782. }
  783.  
  784. /* Check for end of line */
  785.  
  786. void checkeol(void)
  787. {   rdtoken();
  788.     if (tokentype != typeeol) errsyntax("end of line expected");
  789. }
  790.  
  791. /* Skip to semicolon */
  792.  
  793. void skipsemi(void)
  794. {   for (;;)
  795.     {   rdtoken();
  796.         if (tokentype == typesemi) break;
  797.     }
  798. }
  799.  
  800. /* Skip to end of line */
  801.  
  802. void skipeol(void)
  803. {   int ch;
  804.     for (;;)
  805.     {   ch = rdch();
  806.         if (ch == EOF)
  807.         {   unrdch(EOF);
  808.             break;
  809.         }
  810.         if (ch == '\n') break;
  811.     }
  812. }
  813.  
  814. /* Skip white space */
  815.  
  816. void skipspace(void)
  817. {   int ch;
  818.     for (;;)
  819.     {   ch = rdch();
  820.         if (ch != ' ' && ch != '\t') break;
  821.     }
  822.     unrdch(ch);
  823. }
  824.  
  825. /* Read next character */
  826.  
  827. int rdch(void)
  828. {   int ch;
  829.     if (urch == NOURCH)
  830.     {   ch = getc(currentfptr);
  831.         if (ch == EOF)
  832.         {   if (ferror(currentfptr)) errsyntax("file read error");
  833.             return EOF;
  834.         }
  835.         if      (ch == '\n')
  836.         {   ch = getc(currentfptr);
  837.             if (ch != '\r' && ch != EOF) ungetc(ch, currentfptr);
  838.             ch = '\n';
  839.             lineno++;
  840.         }
  841.         else if (ch == '\r')
  842.         {   ch = '\n';
  843.             lineno++;
  844.         }
  845.     }
  846.     else
  847.     {   ch = urch;
  848.         urch = NOURCH;
  849.     }
  850.     return ch;
  851. }
  852.  
  853. /* Unread last character */
  854.  
  855. void unrdch(int ch)
  856. {   urch = ch;
  857. }
  858.  
  859. /* Syntax error */
  860.  
  861. void errsyntax(char *str)
  862. {   fprintf(stderr, "mkmetric: syntax error in \"%s\", line %d - %s\n",
  863.             currentfile, lineno, str);
  864.     longjmp(errjmp, 20);
  865. }
  866.  
  867. /* File size error */
  868.  
  869. void errfilesize(void)
  870. {   fprintf(stderr, "mkmetric: file memory size exceeded\n");
  871.     longjmp(errjmp, 20);
  872. }
  873.  
  874. /* Memory allocation error */
  875.  
  876. void errmemory(void)
  877. {   fprintf(stderr, "mkmetric: memory exhausted\n");
  878.     longjmp(errjmp, 20);
  879. }
  880.  
  881. /* Make a kerning pair */
  882.  
  883. void makekern(int code, int pair, int kern)
  884. {   short *kvec;
  885.     kvec = kerntable[code];
  886.     if (kvec == NULL)
  887.     {   kvec = allocmem(256 * sizeof (short));
  888.         if (kvec == NULL) errmemory();
  889.         kerntable[code] = kvec;
  890.     }
  891.     kvec[pair] = kern;
  892. }
  893.  
  894. /* Build the kerning (sparse) array */
  895.  
  896. int buildkern(int maxlen)
  897. {   struct mkern_entry entry;
  898.     short *ivec;
  899.     int i, j;
  900.     int moff, ioff, xoff;
  901.  
  902.     if (maxlen < 512 * sizeof (struct mkern_entry)) errfilesize();
  903.  
  904.     moff = maxlen / sizeof (struct mkern_entry) - 256;
  905.     xoff = 0;
  906.  
  907.     for (i = lochar; i <= hichar; i++)
  908.     {   ivec = kerntable[i];
  909.         if (ivec == NULL) continue;
  910.         ioff = 256;
  911.         for (;;)
  912.         {   if (ioff >= moff) errfilesize();
  913.             for (j = lochar; j <= hichar; j++)
  914.             {   if (ivec[j] != 0)
  915.                     if (kernbeg[ioff + j].mk_value != 0) goto retry;
  916.             }
  917.             break;
  918.  
  919. retry:      ioff++;
  920.         }
  921.  
  922.         if (ioff > xoff) xoff = ioff;
  923.         entry.mk_value = ioff;
  924.         entry.mk_code = i;
  925.         kernbeg[i] = entry;
  926.         for (j = lochar; j <= hichar; j++)
  927.         {   if (ivec[j] != 0)
  928.             {   entry.mk_value = ivec[j];
  929.                 entry.mk_code = i;
  930.                 kernbeg[ioff + j] = entry;
  931.             }
  932.         }
  933.     }
  934.  
  935.     return (int) ((ioff + 256) * sizeof (struct mkern_entry));
  936. }
  937.  
  938. /* Make a string */
  939.  
  940. char *makestring(char *str)
  941. {   char *s;
  942.     s = allocmem(strlen(str) + 1);
  943.     if (s == NULL) errmemory();
  944.     strcpy(s, str);
  945.     return s;
  946. }
  947.  
  948. /* Allocate memory */
  949.  
  950. void *allocmem(int size)
  951. {   char *ptr;
  952.     int msize;
  953.     msize = (size + 3) & ~3;
  954.     if (msize > memfree)
  955.     {   if (msize > memsize) return NULL;
  956.         if (memsegs == 100) return NULL;
  957.         ptr = AllocMem(memsize, MEMF_CLEAR);
  958.         if (ptr == NULL) return NULL;
  959.         membeg[memsegs++] = ptr;
  960.         memptr = ptr;
  961.         memfree = memsize;
  962.     }
  963.     ptr = memptr;
  964.     memfree -= msize;
  965.     memptr += msize;
  966.     return (void *) ptr;
  967. }
  968.  
  969. /* Free all memory */
  970.  
  971. void freeall(void)
  972. {   while (memsegs)
  973.     {   memsegs--;
  974.         FreeMem(membeg[memsegs], memsize);
  975.     }
  976. }
  977.  
  978. /* Dummy stub routine */
  979.  
  980. void stub(void)
  981. {   return;
  982. }
  983.  
  984. /* Dummy check abort routine */
  985.  
  986. void chkabort(void)
  987. {   return;
  988. }
  989.  
  990. /* End of file "mkmetric.c" */
  991.