134114Skarels #ifndef lint
234114Skarels static char Notice[] = "Copyright (c) 1985 Adobe Systems Incorporated";
334114Skarels static char *RCSID="$Header: pscatmap.c,v 2.1 85/11/24 11:50:07 shore Rel $";
434114Skarels #endif
534114Skarels /* pscatmap.c
634114Skarels  *
734114Skarels  * Copyright (C) 1985 Adobe Systems Incorporated
834114Skarels  *
934114Skarels  * Build font width files for troff and correspondence tables
1034114Skarels  * for pscat.
1134114Skarels  *
1234114Skarels  * Edit History:
1334114Skarels  * Andrew Shore: Sat Nov  9 15:37:04 1985
1434114Skarels  * End Edit History.
1534114Skarels  *
1634114Skarels  * The correspondence tables are intended to be created by humans for
1734114Skarels  * describing a set of 4 fonts to be used by troff: detailing the
1834114Skarels  * mapping from troff & C/A/T codes to output actions for pscat
1934114Skarels  * These actions take one of three forms:
2034114Skarels  *	PFONT	- map to a character in a PostScript font
2134114Skarels  *	PLIG	- map to a "fake" ligature
2234114Skarels  *	PPROC	- map to a named PostScript procedure
2334114Skarels  *	PNONE	- no action
2434114Skarels  *
2534114Skarels  * PFONT is straightforward, the mapping specifies which character in
2634114Skarels  * which PostScript font is desired and the character width is
2734114Skarels  * collected from the PostScript "afm" font metrics file format.
2834114Skarels  * Note that ascender and descender information is "wired in" to the code;
2934114Skarels  * it might be a better idea to "compute" it from the character
3034114Skarels  * bounding box information.
3134114Skarels  *
3234114Skarels  * PLIG is provided so that the correct width for the ligature may
3334114Skarels  * be "computed" by this program, rather than hand done by the user.
3434114Skarels  * There are 3 ligature types:
3534114Skarels  *	0126	- build "ff" out of "f" and "f"
3634114Skarels  *	0131	- build "ffi" out of "f" and "fi"
3734114Skarels  *	0130	- build "ffl" out of "f" and "fl"
3834114Skarels  * This list should probably be expanded to span the space.
3934114Skarels  *
4034114Skarels  * PPROC provides a general callback mechanism so that users can
4134114Skarels  * create and character definition with a PostScript procedure.
4234114Skarels  * The procedures are "named" with user-specified numbers, and are
4334114Skarels  * called with all information available to them (current position,
4434114Skarels  * font size, intended width, railmag, ...).  Such procedures are used
4534114Skarels  * for troff characters not in any PostScript font (rules, boxes,
4634114Skarels  * constructed braces, etc.), but may also be used as a general
4734114Skarels  * "escape hatch" for incorporating ANY PostScript routine into a
4834114Skarels  * troff document -- a logo, a scanned image, etc.  The exact
4934114Skarels  * calling rules are:
5034114Skarels  *	an absolute moveto is performed to the position for this character
5134114Skarels  *	The following numbers are pushed on the PS stack:
5234114Skarels  *	pointsize
5334114Skarels  *	troff character code
5434114Skarels  *	"railmag"
5534114Skarels  *	character width
5634114Skarels  *	procedure "number"
5734114Skarels  *	x offset
5834114Skarels  *	y offset
5934114Skarels  *	width
6034114Skarels  *
6134114Skarels  *	then a procedure named "PSn" where n is the procedure number
6234114Skarels  *	is executed.  It is that procedure's responsibility to image
6334114Skarels  *	the character and move by the appropriate width.
6434114Skarels  *
6534114Skarels  * RCSLOG:
6634114Skarels  * $Log:	pscatmap.c,v $
6734114Skarels  * Revision 2.1  85/11/24  11:50:07  shore
6834114Skarels  * Product Release 2.0
6934114Skarels  *
7034114Skarels  * Revision 1.3  85/11/20  00:32:45  shore
7134114Skarels  * support for System V
7234114Skarels  * short names, non ".c" output, better arith.
7334114Skarels  *
7434114Skarels  * Revision 1.2  85/05/14  11:24:04  shore
7534114Skarels  *
7634114Skarels  *
7734114Skarels  *
7834114Skarels  */
7934114Skarels 
8034114Skarels #include <stdio.h>
8134114Skarels #ifdef SYSV
8234114Skarels #include <string.h>
8334114Skarels #else
8434114Skarels #include <strings.h>
8534114Skarels #endif
8634114Skarels #include "transcript.h"
8734114Skarels #include "action.h"
8834114Skarels 
8934114Skarels #define LFONT 1
9034114Skarels #define LMAP 2
9134114Skarels #define LNONE 3
9234114Skarels 
9334114Skarels private char linebuf[200];
9434114Skarels private char *libdir;		/* place for AFM files */
9534114Skarels 
9634114Skarels private struct chAction chAction [] = {
9734114Skarels     PFONT,	"PFONT",	/* character in PostScript font */
9834114Skarels     PLIG,	"PLIG",		/* fake ligatures: ff ffi ffl */
9934114Skarels     PPROC,	"PPROC",	/* PostScript procedure outcall */
10034114Skarels     PNONE,	"0",		/* null action */
10134114Skarels     0,		0
10234114Skarels };
10334114Skarels 
10434114Skarels #define MAXFONTS 25
10534114Skarels private int nfonts;
10634114Skarels private struct font {
10734114Skarels     char mapname[20];	/* short name in map file e.g., "ROMAN" */
10834114Skarels     char afmname[80];	/* name of AFM file for this font (in map file) */
10934114Skarels     char psname[80];	/* PS font name from AFM file */
11034114Skarels     int  widths[256];   /* PostScript widths of encoded chars (1000/em) */
11134114Skarels     /* more here */
11234114Skarels } fonts[MAXFONTS];
11334114Skarels private char	faces[] = "RIBS0"; /* order important! */
11434114Skarels 
11534114Skarels private char	familyname[80];
11634114Skarels private char	facenames[4][80];
11734114Skarels 
11834114Skarels /* there should be on the order of 4 * 128 characters, so 1000 is generous */
11934114Skarels 
12034114Skarels #define MAXCHARS 1000
12134114Skarels private struct ctab {
12234114Skarels     int		trcode;			/* troff char code */
12334114Skarels     int		catcode;		/* CAT char code */
12434114Skarels     int		wid;			/* table-driven width */
12534114Skarels     int		action;			/* action type */
12634114Skarels     int		x, y;			/* x and y offset */
12734114Skarels     int		font;			/* PostScript font */
12834114Skarels     int		pschar;			/* PS character code */
12934114Skarels     int		pswidth;		/* PS width (/1000) */
13034114Skarels     char 	*descr;			/* short print description */
13134114Skarels } ctab[MAXCHARS];
13234114Skarels private int	nchars;
13334114Skarels 
13434114Skarels 
BuildTable()13534114Skarels private BuildTable()
13634114Skarels {
13734114Skarels     char *c;
13834114Skarels     int status;
13934114Skarels     int gotfamily, gotfaces, gotfonts, gotmap;
14034114Skarels 
14134114Skarels     gotfamily = gotfaces = gotfonts = gotmap = 0;
14234114Skarels 
14334114Skarels     while(fgets(linebuf, sizeof linebuf, stdin) != NULL) {
14434114Skarels 	/* strip off newline */
14534114Skarels 	if ((c = INDEX(linebuf, '\n')) == 0) {
14634114Skarels 	    fprintf(stderr, "line too long \"%s\"\n",linebuf);
14734114Skarels 	    exit(1);
14834114Skarels 	}
14934114Skarels 	*c = '\0';
15034114Skarels 	/* ignore blank or comment (%) lines */
15134114Skarels 	if ((*linebuf == '%') || (*linebuf == '\0')) continue;
15234114Skarels 	if (*linebuf == '@') {
15334114Skarels 	    /* "command" line */
15434114Skarels 	    /* printf("C: %s\n", linebuf); */
15534114Skarels 	    if (strncmp(&linebuf[1], "FAMILYNAME", 10) == 0) {
15634114Skarels 		if (sscanf(linebuf,"@FAMILYNAME %s",familyname) != 1) {
15734114Skarels 		    fprintf(stderr,"bad familyname %s\n",familyname);
15834114Skarels 		    exit(1);
15934114Skarels 		}
16034114Skarels 		gotfamily++;
16134114Skarels 	    }
16234114Skarels 	    if (strncmp(&linebuf[1], "FACENAMES", 9) == 0) {
16334114Skarels 		if (sscanf(linebuf,"@FACENAMES %s %s %s %s",
16434114Skarels 			facenames[0],facenames[1],
16534114Skarels 			facenames[2],facenames[3]) != 4) {
16634114Skarels 		    fprintf(stderr,"must be four facenames\n");
16734114Skarels 		    exit(1);
16834114Skarels 		}
16934114Skarels 		gotfaces++;
17034114Skarels 	    }
17134114Skarels 	    if (strcmp(&linebuf[1], "BEGINFONTS") == 0) {
17234114Skarels 		if ((!gotfamily) || (!gotfaces)) {
17334114Skarels 		    fprintf(stderr,"FAMILYNAME and FACENAMES must come before BEGINFONTS\n");
17434114Skarels 		    exit(1);
17534114Skarels 		}
17634114Skarels 		VOIDC strcpy(fonts[0].mapname,"0");
17734114Skarels 		VOIDC strcpy(fonts[0].afmname,"0");
17834114Skarels 		VOIDC strcpy(fonts[0].psname,"0");
17934114Skarels 		nfonts = 1;
18034114Skarels 		status = LFONT;
18134114Skarels 		continue;
18234114Skarels 	    }
18334114Skarels 	    if (strcmp(&linebuf[1], "ENDFONTS") == 0) {
18434114Skarels 		gotfonts++;
18534114Skarels 		status = LNONE;
18634114Skarels 		continue;
18734114Skarels 	    }
18834114Skarels 	    if (strcmp(&linebuf[1], "BEGINMAP") == 0) {
18934114Skarels 		if (!gotfonts) {
19034114Skarels 		    fprintf(stderr,"BEGINFONTS/ENDFONTS must come before map\n");
19134114Skarels 		    exit(1);
19234114Skarels 		}
19334114Skarels 		status = LMAP;
19434114Skarels 		continue;
19534114Skarels 	    }
19634114Skarels 	    if (strcmp(&linebuf[1], "ENDMAP") == 0) {
19734114Skarels 		status = LNONE;
19834114Skarels 		gotmap++;
19934114Skarels 		continue;
20034114Skarels 	    }
20134114Skarels 	}
20234114Skarels 	switch (status) {
20334114Skarels 	    case LFONT:
20434114Skarels 		GetFont();
20534114Skarels 		break;
20634114Skarels 	    case LMAP:
20734114Skarels 		GetMap();
20834114Skarels 		break;
20934114Skarels 	    default:
21034114Skarels 		break;
21134114Skarels 	}
21234114Skarels     }
21334114Skarels     if (!gotmap) {
21434114Skarels 	fprintf(stderr,"missing @ENDMAP\n");
21534114Skarels 	exit(1);
21634114Skarels     }
21734114Skarels }
21834114Skarels 
GetFont()21934114Skarels private GetFont () {
22034114Skarels     char   *eqp;
22134114Skarels     register int    i;
22234114Skarels     char   afmpath[200];
22334114Skarels #ifdef SYSV
22434114Skarels     char   shortname[40];
22534114Skarels #endif
22634114Skarels 
22734114Skarels     if ((eqp = INDEX(linebuf, '=')) == 0) {
22834114Skarels 	fprintf(stderr, "bad FONTS line:%s\n",linebuf);
22934114Skarels 	exit(1);
23034114Skarels     }
23134114Skarels     *eqp++ = '\0';
23234114Skarels     for (i = 0; i < nfonts; i++) {
23334114Skarels 	if (strcmp (fonts[i].mapname, linebuf) == 0) {
23434114Skarels 	    fprintf(stderr, "duplicate entry for font %s\n", linebuf);
23534114Skarels 	    exit(1);
23634114Skarels 	}
23734114Skarels     }
23834114Skarels     if (nfonts >= MAXFONTS) {
23934114Skarels 	fprintf(stderr, "Too many FONTS\n");
24034114Skarels 	exit(1);
24134114Skarels     }
24234114Skarels     if (strlen(linebuf) > (sizeof fonts[0].mapname)) {
24334114Skarels 	fprintf(stderr, "FONT name too long %s\n", linebuf);
24434114Skarels 	exit(1);
24534114Skarels     }
24634114Skarels     if (strlen(eqp) > (sizeof fonts[0].afmname)) {
24734114Skarels 	fprintf(stderr, "FONT name too long %s\n", eqp);
24834114Skarels 	exit(1);
24934114Skarels     }
25034114Skarels     VOIDC strcpy(fonts[nfonts].mapname, linebuf);
25134114Skarels     VOIDC strcpy(fonts[nfonts].afmname, eqp);
25234114Skarels 
25334114Skarels     /* read the font's .afm file to get real widths */
25434114Skarels     if (*eqp == '/') {
25534114Skarels 	VOIDC strcpy(afmpath,eqp);
25634114Skarels     }
25734114Skarels     else {
25834114Skarels 	VOIDC strcpy(afmpath,libdir);
25934114Skarels 	VOIDC strcat(afmpath,"/");
26034114Skarels #ifdef SYSV
26134114Skarels 	mapname(eqp,shortname);
26234114Skarels 	VOIDC strcat(afmpath,shortname);
26334114Skarels #else
26434114Skarels 	VOIDC strcat(afmpath, eqp);
26534114Skarels #endif
26634114Skarels 	VOIDC strcat(afmpath,".afm");
26734114Skarels     }
26834114Skarels     ReadAFM(afmpath);
26934114Skarels     nfonts++;
27034114Skarels     return;
27134114Skarels }
27234114Skarels 
27334114Skarels 
ReadAFM(afmfile)27434114Skarels private ReadAFM(afmfile) char *afmfile; {
27534114Skarels     char *c;
27634114Skarels     FILE *afm;
27734114Skarels     int gotMetrics, gotName, inChars, ccode, cwidth;
27834114Skarels     char afmbuf[1000];
27934114Skarels 
28034114Skarels     if ((afm = fopen(afmfile, "r")) == NULL) {
28134114Skarels 	fprintf(stderr,"Can't open afm file %s\n",afmfile);
28234114Skarels 	exit(1);
28334114Skarels     }
28434114Skarels     inChars = gotMetrics = gotName = 0;
28534114Skarels     while(fgets(afmbuf, sizeof afmbuf, afm) != NULL) {
28634114Skarels 	/* strip off newline */
28734114Skarels 	if ((c = INDEX(afmbuf, '\n')) == 0) {
28834114Skarels 	    fprintf(stderr, "AFM line too long %s\n", afmbuf);
28934114Skarels 	    exit(1);
29034114Skarels 	}
29134114Skarels 	*c = '\0';
29234114Skarels 	/* ignore blank lines */
29334114Skarels 	if (*afmbuf == '\0') continue;
294*34115Skarels 	if (strcmp(afmbuf,"StartFontMetrics 2.0") == 0) {
29534114Skarels 	    gotMetrics++;
29634114Skarels 	    continue;
29734114Skarels 	}
29834114Skarels 	if (strncmp(afmbuf,"FontName ", 9) == 0) {
29934114Skarels 	    VOIDC sscanf(afmbuf,"FontName %s",fonts[nfonts].psname);
30034114Skarels 	    gotName++;
30134114Skarels 	    continue;
30234114Skarels 	}
30334114Skarels 	if (strcmp(afmbuf,"EndCharMetrics") == 0) {
30434114Skarels 	    if (!inChars) {
30534114Skarels 		fprintf(stderr,"AFM: %s without StartCharMetrics\n",afmbuf);
30634114Skarels 		exit(1);
30734114Skarels 	    }
30834114Skarels 	    inChars++;
30934114Skarels 	    break;
31034114Skarels 	}
31134114Skarels 	if (strcmp(afmbuf,"StartCharMetrics") == 0) {
31234114Skarels 	    inChars++;
31334114Skarels 	    continue;
31434114Skarels 	}
31534114Skarels 	if (inChars == 1) {
31634114Skarels 	    if (sscanf(afmbuf,"C %d ; WX %d ;",&ccode, &cwidth) != 2) {
31734114Skarels 		fprintf(stderr, "Bad Character in AFM file %s\n",afmbuf);
31834114Skarels 		exit(1);
31934114Skarels 	    }
32034114Skarels 	    if (ccode == -1) continue; /* skip unencoded chars */
32134114Skarels 	    if (ccode > 255) {
32234114Skarels 		fprintf(stderr, "Bad Character Code skipped %s\n", afmbuf);
32334114Skarels 		continue;
32434114Skarels 	    }
32534114Skarels 	    fonts[nfonts].widths[ccode] = cwidth;
32634114Skarels 	    continue;
32734114Skarels 	}
32834114Skarels     }
32934114Skarels     if ((inChars != 2) || (!gotMetrics) || (!gotName)) {
33034114Skarels 	fprintf(stderr,"improper AFM file %s\n",afmfile);
33134114Skarels 	exit(1);
33234114Skarels     }
33334114Skarels     VOIDC fclose(afm);
33434114Skarels }
33534114Skarels 
33634114Skarels 
GetMap()33734114Skarels private GetMap(){
33834114Skarels     int		trcode;
33934114Skarels     char	trfont;
34034114Skarels     int		catcode;
34134114Skarels     int		wid;
34234114Skarels     char	action[10];
34334114Skarels     int		x,y;
34434114Skarels     char	psfont[20];
34534114Skarels     int		pschar;
34634114Skarels     char	descr[100];
34734114Skarels 
34834114Skarels     char	*fp;
34934114Skarels     int		trface;  /* 0 - 3  : R I B S */
35034114Skarels     int		pf;
35134114Skarels     struct ctab *ch;
35234114Skarels     struct chAction *act;
35334114Skarels 
35434114Skarels     if (sscanf(linebuf,"%o %c %o %d %s %d %d %s %o \"%[^\"]\"",
35534114Skarels         &trcode, &trfont, &catcode, &wid, action, &x, &y,
35634114Skarels 	psfont, &pschar, descr) != 10) {
35734114Skarels 	fprintf(stderr,"Bad line %s",linebuf);
35834114Skarels     }
35934114Skarels 
36034114Skarels     /* verify the integrity of the data we got */
36134114Skarels     if ((fp = INDEX(faces, trfont)) == 0) {
36234114Skarels 	fprintf(stderr, "Bad face code in %s\n", linebuf);
36334114Skarels 	exit(1);
36434114Skarels     }
36534114Skarels     trface = fp - faces;
36634114Skarels     for (act = chAction; act->actName != 0; act++) {
36734114Skarels 	if (strcmp(action, act->actName) == 0) break;
36834114Skarels     }
36934114Skarels     if (act->actName == 0) {
37034114Skarels 	fprintf(stderr, "Bad action in %s\n", linebuf);
37134114Skarels 	exit(1);
37234114Skarels     }
37334114Skarels     for (pf = 0; pf < nfonts; pf++) {
37434114Skarels 	if (strcmp(fonts[pf].mapname, psfont) == 0) goto gotfont;
37534114Skarels     }
37634114Skarels     fprintf(stderr, "Bad font (%s) name %s\n", linebuf, psfont);
37734114Skarels     exit(1);
37834114Skarels 
37934114Skarels     gotfont:
38034114Skarels 
38134114Skarels     if (nchars >= MAXCHARS) {
38234114Skarels 	fprintf(stderr,"Too many character definitions\n");
38334114Skarels 	exit(1);
38434114Skarels     }
38534114Skarels     ch = &ctab[nchars];
38634114Skarels     ch->trcode = trcode;
38734114Skarels     ch->catcode = (trface << 7) | catcode;
38834114Skarels     ch->action = act->actCode;
38934114Skarels     ch->x = x;
39034114Skarels     ch->y = y;
39134114Skarels     ch->font = pf;
39234114Skarels     ch->pschar = pschar;
39334114Skarels     if (descr[0]) {
39434114Skarels 	if ((ch->descr = malloc((unsigned) (strlen(descr)+1))) == NULL) {
39534114Skarels 	    fprintf(stderr,"malloc failed\n");
39634114Skarels 	    exit(1);
39734114Skarels 	}
39834114Skarels 	VOIDC strcpy(ch->descr, descr);
39934114Skarels     }
40034114Skarels 
40134114Skarels     /* calculate width in cat units (432 per inch) of 6 pt
40234114Skarels      * character (the way troff wants them).
40334114Skarels      * 6 pts = 36 cat units
40434114Skarels      */
40534114Skarels 
40634114Skarels     if (ch->action == PLIG) {/* fake ligature, fake width */
40734114Skarels 	switch (catcode) {
40834114Skarels 	    case 0126:	/* ff = f f */
40934114Skarels 		ch->pswidth = fonts[pf].widths['f'] * 2;
41034114Skarels 		break;
41134114Skarels 	    case 0131: /* ffi = f fi */
41234114Skarels 		ch->pswidth = fonts[pf].widths['f'] + fonts[pf].widths[0256];
41334114Skarels 		break;
41434114Skarels 	    case 0130: /* ffl = f fl */
41534114Skarels 	    	ch->pswidth = fonts[pf].widths['f'] + fonts[pf].widths[0257];
41634114Skarels 		break;
41734114Skarels 	    default:
41834114Skarels 		fprintf(stderr,"Unknown ligature 0%o\n",catcode);
41934114Skarels 		exit(1);
42034114Skarels 	}
42134114Skarels     }
42234114Skarels     else {
42334114Skarels 	ch->pswidth = fonts[pf].widths[pschar];
42434114Skarels     }
42534114Skarels     ch->wid = (wid >= 0) ? wid :
42634114Skarels     	(int) ( (((float) ch->pswidth * 36.0 ) / 1000.0) + 0.5);
42734114Skarels     if (ch->wid > 255) {
42834114Skarels 	fprintf(stderr,"Scaled width too big!\n");
42934114Skarels 	exit(1);
43034114Skarels     }
43134114Skarels     nchars++;
43234114Skarels }
43334114Skarels 
43434114Skarels 
compCTent(a,b)43534114Skarels private int compCTent(a,b)
43634114Skarels struct ctab *a, *b;
43734114Skarels {
43834114Skarels     if (a->catcode < b->catcode) return -1;
43934114Skarels     if (a->catcode > b->catcode) return 1;
44034114Skarels     return 0;
44134114Skarels }
44234114Skarels 
44334114Skarels 
WriteTable()44434114Skarels private WriteTable() {
44534114Skarels     int	i, curcode;
44634114Skarels     struct ctab *ct;
44734114Skarels     struct map map, emptymap;
44834114Skarels     char outname[84];
44934114Skarels     FILE *mapfile;
45034114Skarels 
45134114Skarels     /* write out font mapping */
45234114Skarels     if (familyname[0] == 0) {
45334114Skarels 	fprintf(stderr,"No FAMILYNAME specified!\n");
45434114Skarels 	exit(1);
45534114Skarels     }
45634114Skarels     VOIDC strcpy(outname, familyname);
45734114Skarels     VOIDC strcat(outname, ".ct");
45834114Skarels     if ((mapfile = fopen(outname, "w")) == NULL) {
45934114Skarels 	fprintf(stderr,"can't open output file %s\n", mapfile);
46034114Skarels 	exit(1);
46134114Skarels     }
46234114Skarels     VOIDC putw(nfonts, mapfile);
46334114Skarels     for (i = 0; i < nfonts; i++) {
46434114Skarels 	VOIDC fwrite(fonts[i].psname, sizeof fonts[0].psname, 1, mapfile);
46534114Skarels     }
46634114Skarels     /* sort ctab by catcode */
46734114Skarels     qsort((char *) ctab, nchars, sizeof (struct ctab), compCTent);
46834114Skarels     /* write it out */
46934114Skarels     VOIDC putw(ctab[nchars-1].catcode,mapfile);
47034114Skarels     VOIDC fflush(mapfile);
47134114Skarels     emptymap.wid = emptymap.x = emptymap.y = emptymap.font =
47234114Skarels     emptymap.pschar = emptymap.action = emptymap.pswidth = 0;
47334114Skarels 
47434114Skarels     ct = &ctab[0];
47534114Skarels     curcode = 0;
47634114Skarels     for (i = 0; i < MAXCHARS; i++) {
47734114Skarels 	while (curcode < ct->catcode) {
47834114Skarels 	    VOIDC write(fileno(mapfile), &emptymap, sizeof map);
47934114Skarels 	    curcode++;
48034114Skarels 	}
48134114Skarels 	while ((ct->catcode < curcode) && (ct <= &ctab[nchars])) {
48234114Skarels 	    ct++;
48334114Skarels 	    i++;
48434114Skarels 	}
48534114Skarels 	if (ct >= &ctab[nchars]) break;
48634114Skarels 	map.wid = ct->wid;
48734114Skarels 	map.pswidth = ct->pswidth;
48834114Skarels 	map.x = ct->x;
48934114Skarels 	map.y = ct->y;
49034114Skarels 	map.action = ct->action;
49134114Skarels 	map.pschar = ct->pschar;
49234114Skarels 	map.font = ct->font;
49334114Skarels 	VOIDC write(fileno(mapfile), &map, sizeof map);
49434114Skarels 	ct++;
49534114Skarels 	curcode++;
49634114Skarels     }
49734114Skarels     VOIDC fclose(mapfile);
49834114Skarels }
49934114Skarels 
50034114Skarels 
50134114Skarels /* called by qsort to compare troff codes */
50234114Skarels /* if troff codes are the same, use facecode to decide */
50334114Skarels 
compTRcode(a,b)50434114Skarels private compTRcode(a,b)struct ctab *a, *b;
50534114Skarels {
50634114Skarels     register int i;
50734114Skarels     i = a->trcode - b->trcode;
50834114Skarels     if (i == 0) return ((a->catcode>>7) - (b->catcode>>7));
50934114Skarels     return(i);
51034114Skarels }
51134114Skarels 
51234114Skarels 
DoWidths()51334114Skarels private DoWidths() {
51434114Skarels     int f; /* font index 0-3 */
51534114Skarels 
51634114Skarels     qsort((char *) ctab, nchars, sizeof(struct ctab), compTRcode);
51734114Skarels     for (f = 0; f < 4; f++) {
51834114Skarels 	dofont(f);
51934114Skarels     }
52034114Skarels }
52134114Skarels 
52234114Skarels 
52334114Skarels #define ASCENDER 0200
52434114Skarels #define DESCENDER 0100
52534114Skarels 
52634114Skarels /* note that both is 0300 */
52734114Skarels /* ascenders are:
52834114Skarels  *	b d f h i j k l t beta gamma delta zeta theta lambda xi
52934114Skarels  *	phi psi Gamma Delta  Theta Lambda Xi Pi Sigma
53034114Skarels  *	Upsilon Phi Psi Omega gradient
53134114Skarels  */
53234114Skarels 
53334114Skarels private char Ascenders[] = "bdfhijklt\231\232\233\235\237\242\245\254\256\260\261\262\263\264\264\265\266\270\271\272\273\326";
53434114Skarels 
53534114Skarels /* descenders are:
53634114Skarels  *	g j p q y beta zeta eta mu xi
53734114Skarels  *	rho phi chi psi terminal-sigma
53834114Skarels  */
53934114Skarels 
54034114Skarels private char Descenders[] = "gjpqy\231\235\236\243\245\250\254\255\256\275";
54134114Skarels 
54234114Skarels 
dofont(fontno)54334114Skarels private dofont(fontno)
54434114Skarels int  fontno; /* troff font number 0-3 */
54534114Skarels {
54634114Skarels     char ftfilename[100];
54734114Skarels     FILE *ftfile;	/* generated font widths file */
54834114Skarels     int		wid, curcode;
54934114Skarels     struct	ctab *ct, *cc;
55034114Skarels     int		asde;
55134114Skarels 
55234114Skarels #ifdef SYSV
55334114Skarels     VOIDC sprintf(ftfilename, "ft%s", facenames[fontno]);
55434114Skarels #else
55534114Skarels     VOIDC sprintf(ftfilename, "ft%s.c", facenames[fontno]);
55634114Skarels #endif
55734114Skarels     if ((ftfile = fopen(ftfilename, "w")) == NULL) {
55834114Skarels 	perror(ftfilename);
55934114Skarels 	exit(1);
56034114Skarels     }
56134114Skarels #ifdef BSD
56234114Skarels     fprintf(ftfile, "/* troff width file for %s - %s (%c) */\n",
56334114Skarels     	familyname, facenames[fontno], faces[fontno]);
56434114Skarels     fprintf(ftfile, "char ft%s[256-32] = {\n", facenames[fontno]);
56534114Skarels #endif
56634114Skarels 
56734114Skarels     /* write out entry for each troff character code */
56834114Skarels     /* codes 0-31 (decimal) are not used */
56934114Skarels     /* the first interesting code is 32 (040) - space */
57034114Skarels 
57134114Skarels     ct = ctab;
57234114Skarels     for (curcode = 32; curcode < 256; curcode++) {
57334114Skarels 	while ((ct < &ctab[nchars]) && (ct->trcode < curcode) ||
57434114Skarels 		((ct->trcode == curcode) && ((ct->catcode>>7) < fontno))) {
57534114Skarels 		    ct++;
57634114Skarels 		}
57734114Skarels 	asde = 0;
57834114Skarels 	if ((ct >= &ctab[nchars]) || (curcode != ct->trcode) ||
57934114Skarels 	    ((ct->catcode>>7) != fontno)) {
58034114Skarels 		/* not found */
58134114Skarels 		wid = 0;
58234114Skarels 		cc = 0;
58334114Skarels 	}
58434114Skarels 	else {
58534114Skarels 	    wid = ct->wid;
58634114Skarels 	    cc = ct;
58734114Skarels 	    /* calculate ascender/descender info (heuristic) */
58834114Skarels 	    if (((curcode >= '0') && (curcode <= '9')) ||
58934114Skarels 	    	((curcode >= 'A') && (curcode <= 'Z'))) asde |= ASCENDER;
59034114Skarels 	    if (INDEX(Ascenders, curcode)) asde |= ASCENDER;
59134114Skarels 	    if (INDEX(Descenders, curcode)) asde |= DESCENDER;
59234114Skarels 	}
59334114Skarels #ifdef SYSV
59434114Skarels 	/* for system V we write a binary file of the width bytes */
59534114Skarels 	putc(0377&(wid+asde),ftfile);
59634114Skarels #else
59734114Skarels 	/* for BSD we write a "c" array to be compiled */
59834114Skarels 	fprintf(ftfile, "%d", wid);
59934114Skarels 	if (asde) fprintf(ftfile,"+0%o",asde);
60034114Skarels 	fprintf(ftfile, ",\t%s/* %s */\n",
60134114Skarels 		asde?"":"\t",cc?cc->descr:"NULL");
60234114Skarels #endif
60334114Skarels     }
60434114Skarels #ifdef BSD
60534114Skarels     fprintf(ftfile,"};\n");
60634114Skarels #endif
60734114Skarels     VOIDC fclose(ftfile);
60834114Skarels }
60934114Skarels 
61034114Skarels 
main(argc,argv)61134114Skarels main(argc, argv)
61234114Skarels int argc;
61334114Skarels char **argv;
61434114Skarels {
61534114Skarels     if (argc != 2) {
61634114Skarels 	fprintf(stderr,"usage: pscatmap mapfile\n");
61734114Skarels 	exit(1);
61834114Skarels     }
61934114Skarels     if (freopen(*++argv,"r",stdin) == NULL) {
62034114Skarels 	perror("pscatmap");
62134114Skarels 	exit(1);
62234114Skarels     }
62334114Skarels 
62434114Skarels     if ((libdir = envget("PSLIBDIR")) == NULL) libdir = LibDir;
62534114Skarels 
62634114Skarels     BuildTable();
62734114Skarels     WriteTable();
62834114Skarels     DoWidths();
62934114Skarels }
63034114Skarels 
631