/* $Header: fc.c,v 1.3 87/06/22 12:22:27 toddb Exp $ */
#include <stdio.h>
#include <strings.h>
/*
#include <sys/file.h>
#include <errno.h>
*/
/* #include <malloc.h> */ extern char *malloc(), *realloc();
#include "misc.h"
#include "X.h"
#include "Xproto.h"
#include "fontstruct.h"
#include "font.h"
#include "fc.h" /* used by converters only */
/*
* DESCRIPTION
* pure filter; filename argument only
*
* DISCLAIMER
* not much thought has been given to error recovery.
*/
#define INDICES 256
#define MAXENCODING 0xFFFF
extern char *gets(), *index();
static char *myname; /* initialized from argv[0] */
static char *currentfont;
int linenum = 0; /* for error messages */
int or←glyphPad = 0; /* override glyphPading?? */
int or←bitorder = 0; /* override bitorder?? */
#ifdef vax
int glyphPad = 1; /* default padding for glyphs */
int bitorder = LSBFirst; /* default bitmap bit order */
#else
# ifdef sun
int glyphPad = 4; /* default padding for glyphs */
int bitorder = MSBFirst; /* default bitmap bit order */
# else
# ifdef apollo
int glyphPad = 1; /* default padding for glyphs */
int bitorder = MSBFirst; /* default bitmap bit order */
# else
# ifdef ibm032
int glyphPad = 1; /* default padding for glyphs */
int bitorder = MSBFirst; /* default bitmap bit order */
# else
# ifdef princops
int glyphPad = 4;
int bitorder = MSBFirst;
# else
int glyphPad = 1; /* default padding for glyphs */
int bitorder = MSBFirst; /* default bitmap bit order */
# define UNSPECIFIED
# endif
# endif
# endif
# endif
#endif
/*
* read the next line and keep a count for error messages
*/
char *
getline(s)
char *s;
{
s = gets(s);
linenum++;
while (s) {
int len = strlen(s);
if (len && s[len-1] == '\015')
s[--len] = '\0';
if ((len==0) || prefix(s, "COMMENT")) {
s = gets(s);
linenum++;
} else break;
}
return(s);
}
/*
* malloc and copy a string value. Handle quoted strings.
*/
char *
remember(s)
char *s;
{
char *p, *pp;
/* strip leading white space */
while (*s && (*s == ' ' || *s == '\t'))
s++;
if (*s == 0)
return "";
if (*s != '"') {
pp = s;
/* no white space in value */
for (pp=s; *pp; pp++)
if (*pp == ' ' || *pp == '\t' || *pp == '\015' || *pp == '\n') {
*pp = 0;
break;
}
p = malloc(strlen(s)+1);
strcpy(p, s);
return p;
}
/* quoted string: strip outer quotes and undouble inner quotes */
s++;
pp = p = malloc(strlen(s)+1);
while (*s) {
if (*s == '"') {
if (*(s+1) != '"') {
*p++ = 0;
return pp;
} else {
s++;
}
}
*p++ = *s++;
}
*p++ = 0; /* just in case; space for it allocated above */
return pp;
}
/*
* Invert bit order within each BYTE of an array.
* "In" and "out" may point to the same array.
*/
void
bitorderinvert( in, out, nbytes)
register unsigned char *in;
register unsigned char *out;
register int nbytes;
{
static int BOTableInitialized = 0;
static unsigned char BOTable[256];
if ( !BOTableInitialized)
{
int btabi;
int biti;
for ( btabi=0; btabi<256; btabi++)
for ( biti=0; biti<8; biti++)
if (btabi & 1<<biti)
BOTable[btabi] |= (unsigned)0x80 >> biti;
BOTableInitialized++;
}
while ( nbytes--)
*out++ = BOTable[ *in++];
}
/*
* return TRUE if str is a prefix of buf
*/
prefix(buf, str)
char *buf, *str;
{
return strncmp(buf, str, strlen(str))? FALSE : TRUE;
}
/*
* return TRUE if strings are equal
*/
streq(a, b)
char *a, *b;
{
return strcmp(a, b)? FALSE : TRUE;
}
/*
* make a byte from the first two hex characters in s
*/
unsigned char
hexbyte(s)
char *s;
{
unsigned char b = 0;
register char c;
int i;
for (i=2; i; i--) {
c = *s++;
if ((c >= '0') && (c <= '9'))
b = (b<<4) + (c - '0');
else if ((c >= 'A') && (c <= 'F'))
b = (b<<4) + 10 + (c - 'A');
else if ((c >= 'a') && (c <= 'f'))
b = (b<<4) + 10 + (c - 'a');
else
return 0; /* bad data */
}
return b;
}
/*
* fatal error. never returns.
*/
fatal(msg, p1, p2, p3, p4)
char *msg;
{
fprintf(stderr, "%s: %s:", myname, currentfont);
fprintf(stderr, msg, p1, p2, p3, p4);
if (linenum)
fprintf(stderr, " at line %d\n", linenum);
else
fprintf(stderr, "\n");
exit(1);
}
/*
* these properties will be generated if not already present.
*/
#define NULLPROP (FontPropPtr)0;
FontPropPtr pointSizeProp = NULLPROP;
FontPropPtr familyProp = NULLPROP;
FontPropPtr resolutionProp = NULLPROP;
FontPropPtr xHeightProp = NULLPROP;
FontPropPtr weightProp = NULLPROP;
FontPropPtr quadWidthProp = NULLPROP;
#define GENPROPS 6
BOOL haveFontAscent = FALSE;
BOOL haveFontDescent = FALSE;
/*
* check for known property values
*/
int
specialproperty(pfp, pfi)
FontPropPtr pfp;
FontInfoPtr pfi;
{
if (streq(pfp->name, "FONT←ASCENT") && !pfp->indirect)
{
pfi->fontAscent = pfp->value;
haveFontAscent = TRUE;
return 0;
}
else if (streq(pfp->name, "FONT←DESCENT") && !pfp->indirect)
{
pfi->fontDescent = pfp->value;
haveFontDescent = TRUE;
return 0;
}
else if (streq(pfp->name, "DEFAULT←CHAR") && !pfp->indirect)
{
pfi->chDefault = pfp->value;
return 0;
}
else if (streq(pfp->name , "POINT←SIZE"))
pointSizeProp = pfp;
else if (streq(pfp->name , "FAMILY←NAME"))
familyProp = pfp;
else if (streq(pfp->name , "RESOLUTION"))
resolutionProp = pfp;
else if (streq(pfp->name , "X←HEIGHT"))
xHeightProp = pfp;
else if (streq(pfp->name , "WEIGHT"))
weightProp = pfp;
else if (streq(pfp->name , "QUAD←WIDTH"))
quadWidthProp = pfp;
return 1;
}
computeweight(font)
TempFont *font;
{
int i;
int width = 0, area, bits = 0;
register b;
register unsigned char *p;
for (i=0; i<n1dChars(font->pFI); i++)
width += font->pCI[i].metrics.characterWidth;
area = width*(font->pFI->fontAscent+font->pFI->fontDescent);
for (i=0,p=font->pGlyphs; i<font->pFI->maxbounds.byteOffset; i++,p++)
for (b=(*p); b; b >>= 1)
bits += b & 1;
return (int)((bits*1000.0)/area);
}
main(argc, argv)
int argc;
char * argv[];
{
TempFont font;
FontInfoRec fi;
CharInfoPtr cinfos[INDICES]; /* rows waiting to be allocated */
int bytesGlAlloced = 1024; /* amount now allocated for glyphs
(bytes) */
unsigned char *pGl = (unsigned char *)malloc( bytesGlAlloced);
int bytesGlUsed = 0;
int nGl = 0;
int nchars;
float pointSize;
int xRes, yRes;
char linebuf[BUFSIZ];
char namebuf[100];
char family[100];
char *bdffile = NULL;
unsigned int attributes;
int digitWidths = 0, digitCount = 0, ex = 0;
int char←row, char←col;
int i;
CharInfoRec emptyCharInfo;
myname = argv[0];
argc--, argv++;
while (argc--) {
if (argv[0][0] == '-') {
switch (argv[0][1]) {
case 'p': /* Pad Glyphs to Word boundaries */
switch (argv[0][2]) {
default:
goto usage;
case '1':
case '2':
case '4':
case '8':
glyphPad = argv[0][2] - '0';
break;
}
or←glyphPad = 1;
break;
case 'm':
or←bitorder = 1;
bitorder = MSBFirst;
break;
case 'l':
or←bitorder = 1;
bitorder = LSBFirst;
break;
default:
fprintf(stderr, "bad flag -%c\n", argv[0][1]);
break;
}
} else {
if (bdffile)
usage:
fatal("usage: %s [-p#] [bdf file]", myname);
bdffile = argv[0];
if (freopen( bdffile, "r", stdin) == NULL)
fatal("could not open file %s\n", bdffile);
}
argv++;
}
emptyCharInfo.metrics.leftSideBearing = 0;
emptyCharInfo.metrics.rightSideBearing = 0;
emptyCharInfo.metrics.ascent = 0;
emptyCharInfo.metrics.descent = 0;
emptyCharInfo.metrics.characterWidth = 0;
emptyCharInfo.byteOffset = 0;
emptyCharInfo.exists = FALSE;
emptyCharInfo.metrics.attributes = 0;
for (i = 0; i < INDICES; i++)
cinfos[i] = (CharInfoPtr)NULL;
font.pFI = &fi;
fi.firstRow = INDICES;
fi.lastRow = 0;
fi.chFirst = INDICES;
fi.chLast = 0;
fi.pixDepth = 1;
fi.glyphSets = 1;
fi.chDefault = 0; /* may be overridden by a property */
getline(linebuf);
if ((sscanf(linebuf, "STARTFONT %s", namebuf) != 1) ||
!streq(namebuf, "2.1"))
fatal("bad 'STARTFONT'");
getline(linebuf);
if (sscanf(linebuf, "FONT %s", family) != 1)
fatal("bad 'FONT'");
getline(linebuf);
if (!prefix(linebuf, "SIZE"))
fatal("missing 'SIZE'");
if ((sscanf(linebuf, "SIZE %f%d%d", &pointSize, &xRes, &yRes) != 3))
fatal("bad 'SIZE'");
if (xRes != yRes)
fatal("x and y resolution must be equal");
getline(linebuf);
if (!prefix(linebuf, "FONTBOUNDINGBOX"))
fatal("missing 'FONTBOUNDINGBOX'");
getline(linebuf);
if (prefix(linebuf, "STARTPROPERTIES")) {
int nprops;
FontPropPtr pfp;
sscanf(linebuf, "%*s%d", &nprops);
fi.nProps = nprops;
pfp = (FontPropPtr)malloc((nprops+GENPROPS) * sizeof(FontPropRec));
font.pFP = pfp;
getline(linebuf);
while((nprops-- > 0) && !prefix(linebuf, "ENDPROPERTIES")) {
if (sscanf(linebuf, "%s%d", namebuf, &pfp->value) == 2) {
/* integer value */
pfp->indirect = FALSE;
} else {
/* value is (possibly quoted) string */
pfp->indirect = TRUE;
pfp->value = (INT32)remember(linebuf+strlen(namebuf)+1);
}
pfp->name = (CARD32)remember(namebuf);
if (specialproperty(pfp, &fi))
pfp++;
else
fi.nProps--;
getline(linebuf);
}
if (!prefix(linebuf, "ENDPROPERTIES"))
fatal("missing 'ENDPROPERTIES'");
if (!haveFontAscent || !haveFontDescent)
fatal("must have 'FONT←ASCENT' and 'FONT←DESCENT' properties");
if (nprops != -1)
fatal("%d too few properties", nprops+1);
if (!familyProp) {
fi.nProps++;
pfp->name = (CARD32)("FAMILY←NAME");
pfp->value = (INT32)family;
pfp->indirect = TRUE;
familyProp = pfp++;
}
if (!pointSizeProp) {
fi.nProps++;
pfp->name = (CARD32)("POINT←SIZE");
pfp->value = (INT32)(pointSize*10.0);
pfp->indirect = FALSE;
pointSizeProp = pfp++;
}
if (!weightProp) {
fi.nProps++;
pfp->name = (CARD32)("WEIGHT");
pfp->value = -1; /* computed later */
pfp->indirect = FALSE;
weightProp = pfp++;
}
if (!resolutionProp) {
fi.nProps++;
pfp->name = (CARD32)("RESOLUTION");
pfp->value = (INT32)((xRes*100.0)/72.27);
pfp->indirect = FALSE;
resolutionProp = pfp++;
}
if (!xHeightProp) {
fi.nProps++;
pfp->name = (CARD32)("X←HEIGHT");
pfp->value = -1; /* computed later */
pfp->indirect = FALSE;
xHeightProp = pfp++;
}
if (!quadWidthProp) {
fi.nProps++;
pfp->name = (CARD32)("QUAD←WIDTH");
pfp->value = -1; /* computed later */
pfp->indirect = FALSE;
quadWidthProp = pfp++;
}
} else { /* no properties */
fatal("missing 'PROPERTIES'");
}
getline(linebuf);
if (!prefix(linebuf, "CHARS"))
fatal("missing 'CHARS'");
sscanf(linebuf, "%*s%d", &nchars);
getline(linebuf);
while ((nchars-- > 0) && prefix(linebuf, "STARTCHAR")) {
int t;
int ix; /* counts bytes in a glyph */
int wx; /* x component of width */
int bw; /* bounding-box width */
int bh; /* bounding-box height */
int bl; /* bounding-box left */
int bb; /* bounding-box bottom */
int enc, enc2; /* encoding */
char *p; /* temp pointer into linebuf */
int bytesperrow, row;
char charName[100];
if (sscanf(linebuf, "STARTCHAR %s", charName) != 1)
fatal("bad character name");
getline( linebuf);
if ((t=sscanf(linebuf, "ENCODING %d %d", &enc, &enc2)) < 1)
fatal("bad 'ENCODING'");
if (t == 2 && enc == -1)
enc = enc2;
if (enc == -1) {
fprintf(stderr,
"character '%s'with encoding = -1 ignored at line %d\n",
charName, linenum);
do {
char *s = getline(linebuf);
if (!s)
fatal("Unexpected EOF");
} while (!prefix(linebuf, "ENDCHAR"));
getline(linebuf);
continue;
}
if (enc > MAXENCODING)
fatal("character '%s' has encoding(=%d) too large", charName, enc);
char←row = (enc >> 8) & 0xFF;
char←col = enc & 0xFF;
fi.firstRow = MIN(fi.firstRow, char←row);
fi.lastRow = MAX(fi.lastRow, char←row);
fi.chFirst = MIN(fi.chFirst, char←col);
fi.chLast = MAX(fi.chLast, char←col);
if (!cinfos[char←row])
{
cinfos[char←row] =
(CharInfoPtr)malloc(sizeof(CharInfoRec)*INDICES);
bzero(cinfos[char←row], sizeof(CharInfoRec)*INDICES);
}
getline( linebuf);
if (!prefix(linebuf, "SWIDTH"))
fatal("bad 'SWIDTH'");
getline( linebuf);
sscanf( linebuf, "DWIDTH %d %*d", &wx);
getline( linebuf);
sscanf( linebuf, "BBX %d %d %d %d", &bw, &bh, &bl, &bb);
getline( linebuf);
if (prefix(linebuf, "ATTRIBUTES"))
{
for (p = linebuf + strlen("ATTRIBUTES ");
(*p == ' ') || (*p == '\t');
p ++)
/* empty for loop */ ;
attributes = hexbyte(p)<< 8 + hexbyte(p+2);
getline( linebuf); /* set up for BITMAP which follows */
}
else
attributes = 0;
if (!prefix(linebuf, "BITMAP"))
fatal("missing 'BITMAP'");
/* collect data for generated properties */
if ((strlen(charName) == 1)){
if ((charName[0] >='0') && (charName[0] <= '9')) {
digitWidths += wx;
digitCount++;
} else if (charName[0] == 'x') {
ex = (bh+bb)<=0? bh : bh+bb ;
}
}
cinfos[char←row][char←col].metrics.leftSideBearing = bl;
cinfos[char←row][char←col].metrics.rightSideBearing = bl+bw;
cinfos[char←row][char←col].metrics.ascent = bh+bb;
cinfos[char←row][char←col].metrics.descent = -bb;
cinfos[char←row][char←col].metrics.characterWidth = wx;
cinfos[char←row][char←col].byteOffset = bytesGlUsed;
cinfos[char←row][char←col].exists = FALSE; /* overwritten later */
cinfos[char←row][char←col].metrics.attributes = attributes;
bytesperrow = GLWIDTHBYTESPADDED(bw,glyphPad);
for (row=0; row < bh; row++) {
getline(linebuf);
p = linebuf;
for ( ix=0; ix < bytesperrow; ix++)
{
if ( bytesGlUsed >= bytesGlAlloced)
pGl = (unsigned char *)realloc( pGl, (bytesGlAlloced *= 2));
pGl[bytesGlUsed] = hexbyte(p);
p += 2;
bytesGlUsed++;
}
/*
* Now pad the glyph row our pad boundary.
*/
bytesGlUsed = GLWIDTHBYTESPADDED(bytesGlUsed<<3,glyphPad);
}
getline( linebuf);
if (!prefix(linebuf, "ENDCHAR"))
fatal("missing 'ENDCHAR'");
nGl++;
getline( linebuf); /* get STARTCHAR or ENDFONT */
}
if (!prefix(linebuf, "ENDFONT"))
fatal("missing 'ENDFONT'");
if (nchars != -1)
fatal("%d too few characters", nchars+1);
if (nGl == 0)
fatal("No characters with valid encodings");
fi.maxbounds.byteOffset = bytesGlUsed;
font.pGlyphs = pGl;
font.pCI = (CharInfoPtr)malloc(sizeof(CharInfoRec)*n2dChars(font.pFI));
i = 0;
for (char←row = fi.firstRow; char←row <= fi.lastRow; char←row++)
{
if (!cinfos[char←row])
for (char←col = fi.chFirst; char←col <= fi.chLast; char←col++)
{
font.pCI[i] = emptyCharInfo;
i++;
}
else
for (char←col = fi.chFirst; char←col <= fi.chLast; char←col++)
{
font.pCI[i] = cinfos[char←row][char←col];
i++;
}
}
computeNaccelerators(&font);
/* generate properties */
if (xHeightProp && (xHeightProp->value == -1))
xHeightProp->value = ex? ex : fi.minbounds.metrics.ascent;
if (quadWidthProp && (quadWidthProp->value == -1))
quadWidthProp->value = digitCount?
(INT32)((float)digitWidths/(float)digitCount) :
(fi.minbounds.metrics.characterWidth+fi.maxbounds.metrics.characterWidth)/2;
if (weightProp && (weightProp->value == -1))
weightProp->value = computeweight(&font);
if (bitorder == LSBFirst)
bitorderinvert( pGl, pGl, bytesGlUsed);
#ifdef UNSPECIFIED
if (!or←glyphPad || !or←bitorder) {
fprintf(stderr, "%s: ", currentfont);
if (!or←glyphPad && !or←bitorder)
fprintf(stderr, "bit order/pad unspecified:\n\t");
else if (!or←glyphPad)
fprintf(stderr, "pad unspecified:\n\t");
else
fprintf(stderr, "bit order unspecified:\n\t");
fprintf(stderr, "using ");
if (!or←bitorder)
fprintf(stderr, "order=%s",
bitorder == LSBFirst ? "LSBFirst" : "MSBFirst");
if (!or←glyphPad && !or←bitorder)
fprintf(stderr, ", ");
if (!or←glyphPad)
fprintf(stderr, "pad=%d", glyphPad);
fprintf(stderr, "\n");
}
#endif
WriteNFont( stdout, &font);
exit(0);
}