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 >
Wrap
C/C++ Source or Header
|
1991-06-09
|
25KB
|
991 lines
/* Metric file builder for PPage etc. File "mkmetric.c".
* (C) Adrian Aylward 1991
*
* You may freely copy, use, and modify this file.
*
* This program prints builds a font metric (.metric) file in the format
* used by Professional Page. Its input is one or more Adobe font metric
* (.afm) files.
*
* The program was tested using Lattice C V5.05. It has various Lattice
* dependencies.
*
* This is version 1.1.
*/
# include <dos.h>
# include <exec/exec.h>
# include <proto/dos.h>
# include <proto/exec.h>
# include <string.h>
# include <setjmp.h>
# include <stdio.h>
/* Metric file format */
struct mfile_header
{ int mf_sect[5];
};
struct msect_header
{ char ms_fontname[40];
char ms_filler1[26];
int ms_widthtable;
int ms_kerntable;
char ms_filler2[6];
char ms_fixedpitch; /* 0 = fixed, 1 = variable */
char ms_encoding; /* 0 = font, 1 = standard */
short ms_fontbbox[4];
short ms_underlineposition;
short ms_underlinethickness;
short ms_capheight;
short ms_xheight;
short ms_ascender;
short ms_descender;
short ms_stype;
};
struct mkern_entry
{ short mk_value;
short mk_code;
};
/* External data (initialised to zero) */
char *argmetricfile, *argafmfiles;
char *argencodingfile;
int optfontencoding, optsetfontencoding;
int lochar, hichar;
BPTR newfh;
# define memsize 10000
char *membeg[100], *memptr;
int memsegs, memfree;
# define filesize 100000
char *filemem;
int filelen;
struct mfile_header *mfhdr;
struct msect_header *mshdr;
int sectno, sectbeg;
short *widthbeg;
int kernflag;
struct mkern_entry *kernbeg;
char currentfile[100];
FILE *currentfptr;
# define NOURCH (EOF - 1)
int lineno, urch;
int scanmode;
int retcode;
jmp_buf errjmp;
# define typeeof 0
# define typeeol 1
# define typesemi 2
# define typepercent 3
# define typename 4
# define typeint 5
int tokentype, tokenival;
char namebuf[256];
char charname[256], charpair[256];
char *charstr;
int charcode, charwidth, charkern;
int fontwidth;
int kernsize;
short *kerntable[256];
/* Encoding vector, initially Adobe StandardEncoding */
char *encoding[256] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
"space", "exclam", "quotedbl", "numbersign", /* 20 */
"dollar", "percent", "ampersand", "quoteright",
"parenleft", "parenright", "asterisk", "plus",
"comma", "hyphen", "period", "slash",
"zero", "one", "two", "three", /* 30 */
"four", "five", "six", "seven",
"eight", "nine", "colon", "semicolon",
"less", "equal", "greater", "question",
"at", "A", "B", "C", /* 40 */
"D", "E", "F", "G",
"H", "I", "J", "K",
"L", "M", "N", "O",
"P", "Q", "R", "S", /* 50 */
"T", "U", "V", "W",
"X", "Y", "Z", "bracketleft",
"backslash", "bracketright", "asciicircum", "underscore",
"quoteleft", "a", "b", "c", /* 60 */
"d", "e", "f", "g",
"h", "i", "j", "k",
"l", "m", "n", "o",
"p", "q", "r", "s", /* 70 */
"t", "u", "v", "w",
"x", "y", "z", "braceleft",
"bar", "braceright", "asciitilde", 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, "exclamdown", "cent", "sterling", /* A0 */
"fraction", "yen", "florin", "section",
"currency", "quotesingle", "quotedblleft", "guillemotleft",
"guilsinglleft", "guilsinglright","fi", "fl",
0, "endash", "dagger", "daggerdbl", /* B0 */
"periodcentered",0, "paragraph", "bullet",
"quotesinglbase","quotedblbase", "quotedblright", "guillemotright",
"ellipsis", "perthousand", 0, "questiondown",
0, "grave", "acute", "circumflex", /* C0 */
"tilde", "macron", "breve", "dotaccent",
"dieresis", 0, "ring", "cedilla",
0, "hungarumlaut", "ogonek", "caron",
"emdash", 0, 0, 0, /* D0 */
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, "AE", 0, "ordfeminine",/* E0 */
0, 0, 0, 0,
"Lslash", "Oslash", "OE", "ordmasculine",
0, 0, 0, 0,
0, "ae", 0, 0, /* F0 */
0, "dotlessi", 0, 0,
"lslash", "oslash", "oe", "germandbls",
0, 0, 0, 0
};
/* Routines */
extern int strtoint(char **sp, int *ip);
extern void readencoding(void);
extern void convertafm(void);
extern int mvalue(int val);
extern void rdkey(void);
extern void rdname(void);
extern void rdbool(void);
extern void rdint(void);
extern void rdnumb(void);
extern void rdstring(void);
extern void rdtoken(void);
extern void checksemi(void);
extern void checkeol(void);
extern void skipsemi(void);
extern void skipeol(void);
extern void skipspace(void);
extern int rdch(void);
extern void unrdch(int ch);
extern void errsyntax(char *f);
extern void errfilesize(void);
extern void errmemory(void);
extern void makekern(int code, int pair, int kern);
extern int buildkern(int maxlen);
extern char *makestring(char *str);
extern void *allocmem(int size);
extern void freeall(void);
extern void stub(void);
extern void chkabort(void);
/* Main program */
void main(int argc, char **argv)
{ char *s, *t;
int *ip, i, ch;
/* Parse arguments. No workbench startup */
lochar = 32;
hichar = 255;
if (argc == 0) goto tidyexit;
argv++;
argc--;
if (argc == 0 || (argc == 1 && strcmp(*argv, "?") == 0)) goto query;
while (argc)
{ s = *argv;
if (*s != '-') break;
argv++;
argc--;
if (strcmp(s, "--") == 0) break;
s++;
for (;;)
{ ch = *s++;
if (ch == 0) break;
switch (ch)
{ case 'E': case 'e':
if (argc == 0) goto badargs;
argencodingfile = *argv++;
argc--;
continue;
case 'F': case 'f':
optfontencoding = 1;
continue;
case 'S': case 's':
optsetfontencoding = 1;
continue;
case 'L': case 'l':
ip = &lochar;
break;
case 'H': case 'h':
ip = &hichar;
break;
default:
fprintf(stderr, "mkmetric: unknown option \"-%c\"", ch);
goto badusage;
}
if (!strtoint(&s, ip)) goto badargs;
}
if (*s == '-' && *(s + 1) == 0) break;
}
if (lochar > hichar || hichar > 255)
{ fprintf(stderr, "mkmetric: LoChar/HiChar out of range "
"(0 <= Lo <= Hi <= 255)\n");
goto errorexit;
}
if (argc != 2) goto badargs;
argmetricfile = argv[0];
argafmfiles = argv[1];
if (argencodingfile == NULL) argencodingfile = "PSFonts:encoding.ps";
/* Read the encoding file */
if (optfontencoding == 0)
{ strncpy(currentfile, argencodingfile, 99);
currentfile[99] = 0;
currentfptr = fopen(argencodingfile, "r");
if (currentfptr == NULL)
{ fprintf(stderr, "mkmetric: can't open encoding file %s\n",
argencodingfile);
goto errorexit;
}
readencoding();
if (retcode != 0) goto errorexit;
fclose(currentfptr);
currentfptr = NULL;
}
else
memset((char *) encoding, 0, sizeof (encoding));
/* Allocate the metric file memory */
filemem = AllocMem(filesize, MEMF_CLEAR);
if (filemem == NULL)
{ fprintf(stderr, "mkbmap: can't get metrci file memory\n");
goto errorexit;
}
mfhdr = (void *) filemem;
filelen = sizeof (struct mfile_header);
/* Loop to process all the AFM files */
sectno = 0;
s = argafmfiles;
for (;;)
{ t = s;
while (*t != ',' && *t != 0) t++;
i = t - s;
if (i >= 100)
{ fprintf(stderr, "mkmetric: afm file name too long\n");
goto errorexit;
}
if (i == 0)
{ if (sectno == 0)
{ fprintf(stderr,
"mkmetric: plain version afm file name missing\n");
goto errorexit;
}
}
else
{ memcpy(currentfile, s, i);
currentfile[i] = 0;
currentfptr = fopen(currentfile, "r");
if (currentfptr == NULL)
{ fprintf(stderr,
"mkmetric: can't open afm file %s\n", currentfile);
goto errorexit;
}
mfhdr->mf_sect[sectno] = filelen;
convertafm();
if (retcode != 0) goto errorexit;
fclose(currentfptr);
currentfptr = NULL;
}
sectno++;
if (*t == 0) break;
s = t + 1;
}
mfhdr->mf_sect[4] = filelen;
/* All done. Write out the file an exit */
newfh = Open(argmetricfile, MODE_NEWFILE);
if (newfh == NULL)
{ fprintf(stderr, "mkmetric: can't open metric file %s\n",
argmetricfile);
goto errorexit;
}
i = Write(newfh, (UBYTE *) filemem, filelen);
Close(newfh);
if (i == -1)
{ fprintf(stderr, "mkmetric: error writing metric file %s\n",
argmetricfile);
goto errorexit;
}
goto tidyexit;
/* Argument errors and usage query */
query:
fprintf(stderr, "Metric file builder. MkMetric version 1.1\n"
"Makes PPage .metric files from Adobe .afm files\n"
"\n"
" Usage:\n"
"\n"
" mkmetric -options metricfile "
"plain.afm,bold..,italic..,bolditalic..\n"
"\n"
" -e encodingfile Encoding file name\n"
" -f Font specific encoding\n"
" -s Set font specific encoding\n"
" -n No character names\n");
fprintf(stderr, " -lnnn LoChar\n"
" -hnnn Hichar\n"
"\n"
" For example:\n"
"\n"
" mkmetric fonts:CooperBlack.metric "
"CooperBlack.afm,,CooperBlack-Italic.afm\n");
goto tidyexit;
badargs:
fprintf(stderr, "mkmetric: arguments bad, or value missing");
badusage:
retcode = 20;
fprintf(stderr, ". Usage:\n"
" mkmetric -options metricfile "
"plain.afm,bold..,italic..,bolditalic..\n");
goto tidyexit;
/* Tidy up and exit */
broken:
fprintf(stderr, "mkmetric: *** Break\n");
retcode = 10;
goto tidyexit;
errorexit:
retcode = 20;
tidyexit:
if (currentfptr) fclose(currentfptr);
currentfptr = NULL;
if (filemem) FreeMem(filemem, filesize);
freeall();
exit(retcode);
}
/* String to integer conversion; digits only, with error check */
int strtoint(char **sp, int *ip)
{ char *s = *sp;
int i = 0;
int ch;
for (;;)
{ ch = *s;
if (ch < '0' || ch > '9') break;
i = i * 10 + (ch - '0');
s++;
}
if (s == *sp)
return 0;
else
{ *sp = s;
*ip = i;
return 1;
}
}
/* Read the encoding file */
void readencoding(void)
{ lineno = 1;
urch = NOURCH;
scanmode = 0;
retcode = setjmp(errjmp);
if (retcode != 0) return;
for (;;)
{ rdtoken();
if (tokentype == typeeof) break;
if (tokentype == typeeol) continue;
if (tokentype != typeint) errsyntax("integer expected");
charcode = tokenival;
rdtoken();
if (tokentype != typename) errsyntax("name expected");
if (namebuf[0] == '/')
charstr = makestring(&namebuf[1]);
else
charstr = makestring(&namebuf[0]);
rdtoken();
if (tokentype != typeeol) errsyntax("end of line expected");
if (charcode < 0 || charcode > 255)
errsyntax("character code out of range");
encoding[charcode] = charstr;
}
}
/* Convert a single AFM file */
void convertafm(void)
{ int i, j;
sectbeg = filelen;
mshdr = (void *) (filemem + filelen);
filelen += sizeof (struct msect_header);
if (filelen > filesize) errfilesize();
mshdr->ms_fixedpitch = 1;
mshdr->ms_encoding = (optfontencoding | optsetfontencoding) ? 0 : 1;
mshdr->ms_stype = sectno + 1;
mshdr->ms_widthtable = filelen - sectbeg;
widthbeg = (void *) (filemem + filelen);
filelen += sizeof (short) * 256;
if (filelen > filesize) errfilesize();
lineno = 1;
urch = NOURCH;
scanmode = 1;
retcode = setjmp(errjmp);
if (retcode != 0) return;
kernflag = 0;
for (i = lochar; i <= hichar; i++) kerntable[i] = NULL;
rdkey();
if (strcmp(namebuf, "StartFontMetrics") != 0)
errsyntax("StartFontMetrics expected\n");
skipeol();
rdl:
rdkey();
if (strcmp(namebuf, "EndFontMetrics") == 0)
{ skipeol();
goto eof;
}
if (strcmp(namebuf, "FontName") == 0)
{ rdstring();
strncpy(mshdr->ms_fontname, namebuf, 40);
goto rdl;
}
if (strcmp(namebuf, "FontBBox") == 0)
{ for (i = 0 ; i < 4; i++)
{ rdint();
mshdr->ms_fontbbox[i] = mvalue(tokenival);
}
checkeol();
goto rdl;
}
if (strcmp(namebuf, "CapHeight") == 0)
{ rdnumb();
mshdr->ms_capheight = mvalue(tokenival);
checkeol();
goto rdl;
}
if (strcmp(namebuf, "XHeight") == 0)
{ rdnumb();
mshdr->ms_xheight = mvalue(tokenival);
checkeol();
goto rdl;
}
if (strcmp(namebuf, "Ascender") == 0)
{ rdnumb();
mshdr->ms_ascender = mvalue(tokenival);
checkeol();
goto rdl;
}
if (strcmp(namebuf, "Descender") == 0)
{ rdnumb();
mshdr->ms_descender = mvalue(tokenival);
checkeol();
goto rdl;
}
if (strcmp(namebuf, "UnderlinePosition") == 0)
{ rdnumb();
mshdr->ms_underlineposition = mvalue(tokenival);
checkeol();
goto rdl;
}
if (strcmp(namebuf, "UnderlineThickness") == 0)
{ rdnumb();
mshdr->ms_underlinethickness = mvalue(tokenival);
checkeol();
goto rdl;
}
if (strcmp(namebuf, "CharWidth") == 0)
{ rdnumb();
fontwidth = mvalue(tokenival);
rdnumb();
checkeol();
goto rdl;
}
if (strcmp(namebuf, "IsFixedPitch") == 0)
{ rdbool();
mshdr->ms_fixedpitch = tokenival ? 0 : 1;
checkeol();
goto rdl;
}
if (strcmp(namebuf, "C") == 0)
{ charcode = -1;
charname[0] = 0;
charwidth = fontwidth;
rdint();
charcode = tokenival;
if (charcode > 255) errsyntax("character code out of range");
checksemi();
for (;;)
{ rdtoken();
if (tokentype == typeeol) break;
if (tokentype != typename) errsyntax("key expected");
if (strcmp(namebuf, "N") == 0)
{ rdname();
strcpy(charname, namebuf);
checksemi();
}
else if (strcmp(namebuf, "WX") == 0)
{ rdnumb();
charwidth = mvalue(tokenival);
checksemi();
}
else
skipsemi();
}
if (optfontencoding == 0)
{ if (charname[0] == 0) errsyntax("character name missing");
for (i = lochar; i <= hichar; i++)
if (encoding[i] != NULL &&
strcmp(encoding[i], charname) == 0)
widthbeg[i] = charwidth;
}
else
if (charcode >= lochar && charcode <= hichar)
{ if (charname[0] != 0)
encoding[charcode] = makestring(charname);
widthbeg[charcode] = charwidth;
}
goto rdl;
}
if (strcmp(namebuf, "KPX") == 0)
{ rdname();
strcpy(charname, namebuf);
rdname();
strcpy(charpair, namebuf);
rdnumb();
charkern = mvalue(tokenival);
checkeol();
if (charkern != 0)
for (i = lochar; i <= hichar; i++)
if (encoding[i] != NULL &&
strcmp(encoding[i], charname) == 0)
for (j = lochar; j <= hichar; j++)
if (encoding[j] != NULL &&
strcmp(encoding[j], charname) == 0)
{ kernflag = 1;
makekern(i, j, charkern);
}
goto rdl;
}
skipeol();
goto rdl;
/* End of file. Build the kerning (sparse) array */
eof:
if (kernflag)
{ mshdr->ms_kerntable = filelen - sectbeg;
kernbeg = (void *) (filemem + filelen);
filelen += buildkern(filesize - filelen);
}
}
/* Scale a character coordinate value for the .metric file */
int mvalue(int val)
{ return (val * 1024) / 1000;
}
/* Read key from beginning of line */
void rdkey(void)
{
rdl:
rdtoken();
if (tokentype == typeeol) goto rdl;
if (tokentype != typename) errsyntax("key name expected");
if (strcmp(namebuf, "Comment") == 0)
{ skipeol();
goto rdl;
}
}
/* Read a name */
void rdname(void)
{ rdtoken();
if (tokentype != typename) errsyntax("name expected");
}
/* Read a boolean */
void rdbool(void)
{ rdtoken();
if (tokentype == typename && strcmp(namebuf, "true") == 0)
tokenival = 1;
else if (tokentype == typename && strcmp(namebuf, "false") == 0)
tokenival = 0;
else
errsyntax("boolean expected");
}
/* Read an integer */
void rdint(void)
{ rdtoken();
if (tokentype != typeint) errsyntax("integer expected");
}
/* Read a number (no support for reals) */
void rdnumb(void)
{ rdtoken();
if (tokentype != typeint) errsyntax("number expected");
}
/* Read a string */
void rdstring(void)
{ int i, ch;
skipspace();
i = 0;
for (;;)
{ ch = rdch();
if (ch == EOF || ch == '\n') break;
if (i >= 255) errsyntax("string too long");
namebuf[i++] = ch;
}
namebuf[i] = 0;
unrdch(ch);
}
/* Read the next token */
void rdtoken(void)
{ int val, i, j, ch;
skipspace();
i = 0;
for (;;)
{ ch = rdch();
if (ch == EOF)
{ if (i == 0)
{ tokentype = typeeof;
return;
}
else
break;
}
if (scanmode == 0)
{ if (ch == '%')
{ if (i == 0)
{ skipeol();
tokentype = typeeol;
return;
}
else
break;
}
}
else
{ if (ch == ';')
{ if (i == 0)
{ tokentype = typesemi;
return;
}
else
break;
}
}
if (ch == '\n')
{ if (i == 0)
{ tokentype = typeeol;
return;
}
else
break;
}
if (ch == ' ' || ch == '\t') break;
if (i >= 255) errsyntax("token too long");
namebuf[i++] = ch;
}
namebuf[i] = 0;
unrdch(ch);
tokentype = typename;
{ j = 0;
if (namebuf[0] == '-')
{ j++;
if (i <= j) return;
}
val = 0;
while (j < i)
{ ch = namebuf[j];
if (ch < '0' || ch > '9') return;
val = val * 10 + (ch - '0');
j++;
}
if (namebuf[0] == '-') val = -val;
tokentype = typeint;
tokenival = val;
}
}
/* Check for semicolon */
void checksemi(void)
{ rdtoken();
if (tokentype != typesemi) errsyntax("semicolon expected");
}
/* Check for end of line */
void checkeol(void)
{ rdtoken();
if (tokentype != typeeol) errsyntax("end of line expected");
}
/* Skip to semicolon */
void skipsemi(void)
{ for (;;)
{ rdtoken();
if (tokentype == typesemi) break;
}
}
/* Skip to end of line */
void skipeol(void)
{ int ch;
for (;;)
{ ch = rdch();
if (ch == EOF)
{ unrdch(EOF);
break;
}
if (ch == '\n') break;
}
}
/* Skip white space */
void skipspace(void)
{ int ch;
for (;;)
{ ch = rdch();
if (ch != ' ' && ch != '\t') break;
}
unrdch(ch);
}
/* Read next character */
int rdch(void)
{ int ch;
if (urch == NOURCH)
{ ch = getc(currentfptr);
if (ch == EOF)
{ if (ferror(currentfptr)) errsyntax("file read error");
return EOF;
}
if (ch == '\n')
{ ch = getc(currentfptr);
if (ch != '\r' && ch != EOF) ungetc(ch, currentfptr);
ch = '\n';
lineno++;
}
else if (ch == '\r')
{ ch = '\n';
lineno++;
}
}
else
{ ch = urch;
urch = NOURCH;
}
return ch;
}
/* Unread last character */
void unrdch(int ch)
{ urch = ch;
}
/* Syntax error */
void errsyntax(char *str)
{ fprintf(stderr, "mkmetric: syntax error in \"%s\", line %d - %s\n",
currentfile, lineno, str);
longjmp(errjmp, 20);
}
/* File size error */
void errfilesize(void)
{ fprintf(stderr, "mkmetric: file memory size exceeded\n");
longjmp(errjmp, 20);
}
/* Memory allocation error */
void errmemory(void)
{ fprintf(stderr, "mkmetric: memory exhausted\n");
longjmp(errjmp, 20);
}
/* Make a kerning pair */
void makekern(int code, int pair, int kern)
{ short *kvec;
kvec = kerntable[code];
if (kvec == NULL)
{ kvec = allocmem(256 * sizeof (short));
if (kvec == NULL) errmemory();
kerntable[code] = kvec;
}
kvec[pair] = kern;
}
/* Build the kerning (sparse) array */
int buildkern(int maxlen)
{ struct mkern_entry entry;
short *ivec;
int i, j;
int moff, ioff, xoff;
if (maxlen < 512 * sizeof (struct mkern_entry)) errfilesize();
moff = maxlen / sizeof (struct mkern_entry) - 256;
xoff = 0;
for (i = lochar; i <= hichar; i++)
{ ivec = kerntable[i];
if (ivec == NULL) continue;
ioff = 256;
for (;;)
{ if (ioff >= moff) errfilesize();
for (j = lochar; j <= hichar; j++)
{ if (ivec[j] != 0)
if (kernbeg[ioff + j].mk_value != 0) goto retry;
}
break;
retry: ioff++;
}
if (ioff > xoff) xoff = ioff;
entry.mk_value = ioff;
entry.mk_code = i;
kernbeg[i] = entry;
for (j = lochar; j <= hichar; j++)
{ if (ivec[j] != 0)
{ entry.mk_value = ivec[j];
entry.mk_code = i;
kernbeg[ioff + j] = entry;
}
}
}
return (int) ((ioff + 256) * sizeof (struct mkern_entry));
}
/* Make a string */
char *makestring(char *str)
{ char *s;
s = allocmem(strlen(str) + 1);
if (s == NULL) errmemory();
strcpy(s, str);
return s;
}
/* Allocate memory */
void *allocmem(int size)
{ char *ptr;
int msize;
msize = (size + 3) & ~3;
if (msize > memfree)
{ if (msize > memsize) return NULL;
if (memsegs == 100) return NULL;
ptr = AllocMem(memsize, MEMF_CLEAR);
if (ptr == NULL) return NULL;
membeg[memsegs++] = ptr;
memptr = ptr;
memfree = memsize;
}
ptr = memptr;
memfree -= msize;
memptr += msize;
return (void *) ptr;
}
/* Free all memory */
void freeall(void)
{ while (memsegs)
{ memsegs--;
FreeMem(membeg[memsegs], memsize);
}
}
/* Dummy stub routine */
void stub(void)
{ return;
}
/* Dummy check abort routine */
void chkabort(void)
{ return;
}
/* End of file "mkmetric.c" */