1*23842Sslatteng /*	ch2vft.c	1.6	85/07/03
216037Sslatteng  *
317892Sslatteng  * Font translation to vfont format from character format.
416064Sslatteng  *
516305Sslatteng  *	Use:	ch2vft  [ -i  -s ]  charfile  > vfontfile
616037Sslatteng  *
716037Sslatteng  *		Takes input from charfile (which must be in the format written
817892Sslatteng  *	by one of the xxx2ch programs), converts to vfont format and writes it
917892Sslatteng  *	to stdout.  If charfile is missing, stdin is read.  The -i flag tells
1017892Sslatteng  *	ch2vft to ignore the character codes at the start of each glyph
1117892Sslatteng  *	definition, and pack the glyphs in consecutive code positions starting
1217892Sslatteng  *	with 0.  The -s flag forces ch2vft to include the whole bit-map that
1317892Sslatteng  *	defines the glyph.  Normally, it is trimmed of white space.  This is
1417892Sslatteng  *	usefull for making stipple patterns of fixed size.
1516037Sslatteng  */
1616037Sslatteng 
1716037Sslatteng #include <stdio.h>
1816037Sslatteng #include <vfont.h>
1916037Sslatteng 
2016037Sslatteng 
21*23842Sslatteng #ifdef sun
22*23842Sslatteng #define RES		120	/* for SUN vfont, resolution is 120 */
23*23842Sslatteng #else
2416037Sslatteng #define RES		200	/* for vfont, resolution is 200 */
25*23842Sslatteng #endif
2616037Sslatteng #define MAXLINE		200
2716064Sslatteng #define GLYPHSPACE	(MAXLINE * MAXLINE)
2816037Sslatteng #define MAGICNO		0436
2916037Sslatteng #define DIRSIZ		256	/* vfonts MUST have 256 entries */
3016037Sslatteng #define DIMLIMIT	128
3116037Sslatteng 
3216037Sslatteng 
3316037Sslatteng char *	malloc();
3416037Sslatteng 
3516037Sslatteng struct dispatch g[DIRSIZ];	/* directory of glyph definitions */
3616037Sslatteng struct header	head;		/* font file header */
3716037Sslatteng 
3817892Sslatteng int	code;
3916037Sslatteng int	width, length, maxv, minv, maxh, minh, refv, refh;
4016037Sslatteng int	fileaddr;
4116037Sslatteng 
4216037Sslatteng int	ignorecode = 0;
4316305Sslatteng int	stipple = 0;
4416037Sslatteng FILE *	filep;
4516037Sslatteng char	ibuff[MAXLINE];
4616037Sslatteng char	ebuff[MAXLINE];
4716037Sslatteng char *	glyphs[DIRSIZ];
4816064Sslatteng char	charbits[GLYPHSPACE];	/* place to store bits for a glyph */
4916037Sslatteng 
5016037Sslatteng 
main(argc,argv)5116037Sslatteng main(argc,argv)
5216037Sslatteng int argc;
5316037Sslatteng char **argv;
5416037Sslatteng {
5516037Sslatteng     register int i;
5616037Sslatteng     register int j;
5717892Sslatteng     register int codeindex;
5816037Sslatteng     register char *chp;
5916037Sslatteng     register char *bitp;
6016037Sslatteng     float par;
6116037Sslatteng 
6217892Sslatteng 
6316037Sslatteng     head.magic = MAGICNO;
6416037Sslatteng     head.maxx = head.maxy = head.xtend = 0;
6516037Sslatteng     while (argc > 1 && argv[1][0] == '-') {
6616037Sslatteng 	switch(argv[1][1]) {
6716037Sslatteng 	case 'i':
6816037Sslatteng 		ignorecode = 1;
6916037Sslatteng 		break;
7016305Sslatteng 
7116305Sslatteng 	case 's':
7216305Sslatteng 		stipple = 1;
7316305Sslatteng 		break;
7416037Sslatteng 	default:
7516037Sslatteng 		error("%s, unknown option flag", argv[1]);
7616037Sslatteng 	}
7716037Sslatteng 	argc--; argv++;
7816037Sslatteng     }
7916037Sslatteng 
8016037Sslatteng     if (argc == 2) {
8116037Sslatteng 	if ((filep = fopen (argv[1], "r")) == NULL)
8216037Sslatteng 	    error("can't open file \"%s\"", argv[1]);
8316037Sslatteng     } else filep = stdin;
8416037Sslatteng 
8516037Sslatteng     codeindex = 0;
8616037Sslatteng     for (i = 0; i < DIRSIZ; glyphs[i++] = (char *) 0);
8716037Sslatteng 
8816037Sslatteng     fgets(ibuff, MAXLINE, filep);
8916101Sslatteng     if (strcmp(ibuff, "fontheader\n"))
9016037Sslatteng 	error("not a character font file");
9116037Sslatteng 
9216037Sslatteng     while (fgets(ibuff, MAXLINE, filep) != NULL) {
9316037Sslatteng 	if (index(ibuff, '\n') == 0)
9416037Sslatteng 	    error("input line too long");
9516037Sslatteng 
9616037Sslatteng 	if (ibuff[0] != ':') {
9716037Sslatteng 	    sscanf (ibuff, "%s %f", ebuff, &par);
9817892Sslatteng 	    if (strcmp(ebuff, "res") == 0) {
9916037Sslatteng 		if (((int) (par + 0.5)) != RES)
10016037Sslatteng 		    fprintf(stderr, "ch2vft warning: wrong resolution (%d).\n",
10116037Sslatteng 			(int) (par + 0.5) );
10217892Sslatteng 	    }
10316037Sslatteng 	} else {
10416037Sslatteng 	    if (sscanf (ibuff, ":%d, width = %f", &code, &par) != 2)
10516037Sslatteng 		error("bad glyph header, %s", ibuff);
10617892Sslatteng 	    if (ignorecode) codeindex++; else codeindex = code;
10717892Sslatteng 	    if (codeindex < 0 || codeindex >= DIRSIZ)
10817892Sslatteng 		error("code (%d) out of range", codeindex);
10917892Sslatteng 	    g[codeindex].width = par + 0.5;
11016037Sslatteng 
11116037Sslatteng 	    chp = &charbits[0];
11216037Sslatteng 	    if (fgets(chp, MAXLINE, filep) == NULL)
11316037Sslatteng 		error("unexpected end of input");
11416037Sslatteng 	    width = strlen(chp) - 1;
11516037Sslatteng 	    minh = width;
11616037Sslatteng 	    maxh = 0;
11716064Sslatteng 	    refv = minv = -1;
11816037Sslatteng 
11916037Sslatteng 	    for (length = 0; *chp != '\n'; length++) {
12016064Sslatteng 		if ((length + 1) * width > GLYPHSPACE)
12116064Sslatteng 		    error ("out of glyph space");
12217892Sslatteng 		for (i = 0; i < width; i++, chp++) {
12316037Sslatteng 		    switch (*chp) {
12416037Sslatteng 			case '.':
12516037Sslatteng 				break;
12616037Sslatteng 			case 'x':
12717892Sslatteng 				refh = i;
12816037Sslatteng 				refv = length;
12916037Sslatteng 				*chp = '.';
13016037Sslatteng 				break;
13116037Sslatteng 			case 'X':
13217892Sslatteng 				refh = i;
13316037Sslatteng 				refv = length;
13416037Sslatteng 			case '@':
13516037Sslatteng 			case '*':
13616037Sslatteng 				maxv = length;
13716064Sslatteng 				if (minv < 0) minv = length;
13817892Sslatteng 				if (i < minh) minh = i;
13917892Sslatteng 				if (i > maxh) maxh = i;
14016037Sslatteng 				break;
14116037Sslatteng 			default:
14216037Sslatteng 				error("illegal character '%c' in map.", *chp);
14316037Sslatteng 		    } /* switch */
14417892Sslatteng 		} /* for i */
14516037Sslatteng 		if (fgets(chp, MAXLINE, filep) == NULL)
14616037Sslatteng 			error("unexpected end of input");
14716037Sslatteng 	    } /* for length */
14816064Sslatteng 
14916305Sslatteng 	    if (stipple) {		/* force whole box if making stipples */
15016305Sslatteng 		minv = 0;
15116305Sslatteng 		minh = 0;
15216305Sslatteng 		maxv = length - 1;
15316305Sslatteng 		maxh = width - 1;
15416305Sslatteng 	    }
15516305Sslatteng 
15616064Sslatteng 	    if (refv < 0) error("no reference point in glyph %d.", code);
15716064Sslatteng 	    if (minv < 0) {
15816064Sslatteng 		minv = maxv = refv;
15916064Sslatteng 		minh = maxh = refh;
16016064Sslatteng 	    }
16117892Sslatteng 	    g[codeindex].up = bound(refv - minv);
16217892Sslatteng 	    g[codeindex].down = bound(maxv + 1 - refv);
16317892Sslatteng 	    g[codeindex].right = bound(maxh + 1 - refh);
16417892Sslatteng 	    g[codeindex].left = bound(refh - minh);
165*23842Sslatteng #ifdef sun
166*23842Sslatteng 	    g[codeindex].nbytes = (maxv+1-minv) * ((maxh+16-minh) / 16) * 2;
167*23842Sslatteng #else
16817892Sslatteng 	    g[codeindex].nbytes = (maxv + 1 - minv) * ((maxh + 8 - minh) >> 3);
169*23842Sslatteng #endif
17016037Sslatteng 
17116037Sslatteng 				/* convert from characters to bits */
17217892Sslatteng 	    bitp = (glyphs[codeindex] = malloc(g[codeindex].nbytes)) - 1;
17317892Sslatteng 	    for (i = minv; i <= maxv; i++) {
17416037Sslatteng 		register int bitwidth;
17516037Sslatteng 
17617892Sslatteng 		chp = &charbits[0] + width * i + minh;
17716037Sslatteng 		bitwidth = 0;
17816037Sslatteng 		for (j = minh; j <= maxh; j++, chp++) {
17916037Sslatteng 		    if (--bitwidth < 0) {
18016037Sslatteng 			*++bitp = '\0';
18116037Sslatteng 			bitwidth = 7;
18216037Sslatteng 		    }
18316037Sslatteng 		    if (*chp != '.') *bitp |= 1 << bitwidth;
18416037Sslatteng 		}
185*23842Sslatteng #ifdef sun
186*23842Sslatteng 		if (!((bitp - glyphs[codeindex]) & 1)) *++bitp = '\0';
187*23842Sslatteng #endif
18817892Sslatteng 	    } /* for i */
18916037Sslatteng 	} /* else */
19016037Sslatteng     } /* while */
19116037Sslatteng 
19216037Sslatteng     fileaddr = 0;
19316037Sslatteng     for (i = 0; i < DIRSIZ; i++) {
19416037Sslatteng 	if (glyphs[i] == (char *) 0) {
19516037Sslatteng 	    g[i].nbytes = 0;
19616037Sslatteng 	} else {
19716037Sslatteng 	    g[i].addr = fileaddr;
19816037Sslatteng 	    fileaddr += g[i].nbytes;
19916037Sslatteng 	    if (g[i].up > head.maxy) head.maxy = g[i].up;
20016037Sslatteng 	    if (g[i].down > head.xtend) head.xtend = g[i].down;
20116037Sslatteng 	    if (((int) g[i].left + g[i].right) > head.maxx)
20216037Sslatteng 		head.maxx = g[i].left + (int) g[i].right;
20316037Sslatteng 	}
20416037Sslatteng     }
20516037Sslatteng     head.size = fileaddr;
20616037Sslatteng 
20716037Sslatteng     vwrite((char *) &head, sizeof(head));
20816037Sslatteng     vwrite((char *) &(g[0]), sizeof(g));
20916037Sslatteng     for (i = 0; i < DIRSIZ; i++)
21016037Sslatteng 	if (glyphs[i] != (char *) 0)
21116037Sslatteng 	    vwrite(glyphs[i], g[i].nbytes);
21217892Sslatteng     exit(0);
21316037Sslatteng }
21416037Sslatteng 
21516037Sslatteng 
21617892Sslatteng /*----------------------------------------------------------------------------*
21717892Sslatteng  | Routine:	bound (value)
21817892Sslatteng  |
21917892Sslatteng  | Results:	checks to make sure that the dimensions of a glyph fit into
22017892Sslatteng  |		the vfont format's limitations.  The up, down, right, and left
22117892Sslatteng  |		fields must fit into a byte!), but can be signed.
22217892Sslatteng  *----------------------------------------------------------------------------*/
22317892Sslatteng 
bound(i)22417892Sslatteng bound(i)
22517892Sslatteng {
22617892Sslatteng 	if(i < DIMLIMIT && i >= -DIMLIMIT) return i;
22717892Sslatteng 	error ("dimension out of range");
22817892Sslatteng }
22917892Sslatteng 
23017892Sslatteng 
23117892Sslatteng /*----------------------------------------------------------------------------*
23217892Sslatteng  | Routine:	vwrite (buffer, buffer_size)
23317892Sslatteng  |
23417892Sslatteng  | Results:	writes out character array "buffer" of size "buffer_size"
23517892Sslatteng  |		to standard output in small enough chunks that a pipe could
23617892Sslatteng  |		handle them.
23717892Sslatteng  |
23817892Sslatteng  | Bugs:	this routine shouldn't be needed
23917892Sslatteng  *----------------------------------------------------------------------------*/
24017892Sslatteng 
vwrite(buf,bufsize)24117892Sslatteng vwrite(buf, bufsize)
24216037Sslatteng char *buf;
24317892Sslatteng int bufsize;
24416037Sslatteng {
24516037Sslatteng 	int tsize = 0;
24616037Sslatteng 
24717892Sslatteng 	while (bufsize) {
24816037Sslatteng 		buf += tsize;
24917892Sslatteng 		tsize = bufsize > BUFSIZ ? BUFSIZ : bufsize;
25016037Sslatteng 		if ((tsize = write(1, buf, tsize)) < 0) {
25116064Sslatteng 			perror("ch2vft: write failed");
25216037Sslatteng 			exit(-1);
25316037Sslatteng 		}
25417892Sslatteng 		bufsize -= tsize;
25516037Sslatteng 	}
25616037Sslatteng }
25716037Sslatteng 
25816037Sslatteng 
25917892Sslatteng /*----------------------------------------------------------------------------*
26017892Sslatteng  | Routine:	error (format_string, argument1, argument2.... )
26117892Sslatteng  |
26217892Sslatteng  | Results:	fprints a message to standard error, then exits with error
26317892Sslatteng  |		code 1
26417892Sslatteng  |
26517892Sslatteng  | Side Efct:	This routine does NOT return
26617892Sslatteng  *----------------------------------------------------------------------------*/
26717892Sslatteng 
26816037Sslatteng /*VARARGS1*/
error(string,a1,a2,a3,a4)26916037Sslatteng error(string, a1, a2, a3, a4)
27016037Sslatteng char *string;
27116037Sslatteng {
27216037Sslatteng 	fprintf(stderr, "ch2vft: ");
27316037Sslatteng 	fprintf(stderr, string, a1, a2, a3, a4);
27416037Sslatteng 	fprintf(stderr, "\n");
27517892Sslatteng 	exit(1);
27616037Sslatteng }
277