1 /*	ch2vft.c	1.6	85/07/03
2  *
3  * Font translation to vfont format from character format.
4  *
5  *	Use:	ch2vft  [ -i  -s ]  charfile  > vfontfile
6  *
7  *		Takes input from charfile (which must be in the format written
8  *	by one of the xxx2ch programs), converts to vfont format and writes it
9  *	to stdout.  If charfile is missing, stdin is read.  The -i flag tells
10  *	ch2vft to ignore the character codes at the start of each glyph
11  *	definition, and pack the glyphs in consecutive code positions starting
12  *	with 0.  The -s flag forces ch2vft to include the whole bit-map that
13  *	defines the glyph.  Normally, it is trimmed of white space.  This is
14  *	usefull for making stipple patterns of fixed size.
15  */
16 
17 #include <stdio.h>
18 #include <vfont.h>
19 
20 
21 #ifdef sun
22 #define RES		120	/* for SUN vfont, resolution is 120 */
23 #else
24 #define RES		200	/* for vfont, resolution is 200 */
25 #endif
26 #define MAXLINE		200
27 #define GLYPHSPACE	(MAXLINE * MAXLINE)
28 #define MAGICNO		0436
29 #define DIRSIZ		256	/* vfonts MUST have 256 entries */
30 #define DIMLIMIT	128
31 
32 
33 char *	malloc();
34 
35 struct dispatch g[DIRSIZ];	/* directory of glyph definitions */
36 struct header	head;		/* font file header */
37 
38 int	code;
39 int	width, length, maxv, minv, maxh, minh, refv, refh;
40 int	fileaddr;
41 
42 int	ignorecode = 0;
43 int	stipple = 0;
44 FILE *	filep;
45 char	ibuff[MAXLINE];
46 char	ebuff[MAXLINE];
47 char *	glyphs[DIRSIZ];
48 char	charbits[GLYPHSPACE];	/* place to store bits for a glyph */
49 
50 
51 main(argc,argv)
52 int argc;
53 char **argv;
54 {
55     register int i;
56     register int j;
57     register int codeindex;
58     register char *chp;
59     register char *bitp;
60     float par;
61 
62 
63     head.magic = MAGICNO;
64     head.maxx = head.maxy = head.xtend = 0;
65     while (argc > 1 && argv[1][0] == '-') {
66 	switch(argv[1][1]) {
67 	case 'i':
68 		ignorecode = 1;
69 		break;
70 
71 	case 's':
72 		stipple = 1;
73 		break;
74 	default:
75 		error("%s, unknown option flag", argv[1]);
76 	}
77 	argc--; argv++;
78     }
79 
80     if (argc == 2) {
81 	if ((filep = fopen (argv[1], "r")) == NULL)
82 	    error("can't open file \"%s\"", argv[1]);
83     } else filep = stdin;
84 
85     codeindex = 0;
86     for (i = 0; i < DIRSIZ; glyphs[i++] = (char *) 0);
87 
88     fgets(ibuff, MAXLINE, filep);
89     if (strcmp(ibuff, "fontheader\n"))
90 	error("not a character font file");
91 
92     while (fgets(ibuff, MAXLINE, filep) != NULL) {
93 	if (index(ibuff, '\n') == 0)
94 	    error("input line too long");
95 
96 	if (ibuff[0] != ':') {
97 	    sscanf (ibuff, "%s %f", ebuff, &par);
98 	    if (strcmp(ebuff, "res") == 0) {
99 		if (((int) (par + 0.5)) != RES)
100 		    fprintf(stderr, "ch2vft warning: wrong resolution (%d).\n",
101 			(int) (par + 0.5) );
102 	    }
103 	} else {
104 	    if (sscanf (ibuff, ":%d, width = %f", &code, &par) != 2)
105 		error("bad glyph header, %s", ibuff);
106 	    if (ignorecode) codeindex++; else codeindex = code;
107 	    if (codeindex < 0 || codeindex >= DIRSIZ)
108 		error("code (%d) out of range", codeindex);
109 	    g[codeindex].width = par + 0.5;
110 
111 	    chp = &charbits[0];
112 	    if (fgets(chp, MAXLINE, filep) == NULL)
113 		error("unexpected end of input");
114 	    width = strlen(chp) - 1;
115 	    minh = width;
116 	    maxh = 0;
117 	    refv = minv = -1;
118 
119 	    for (length = 0; *chp != '\n'; length++) {
120 		if ((length + 1) * width > GLYPHSPACE)
121 		    error ("out of glyph space");
122 		for (i = 0; i < width; i++, chp++) {
123 		    switch (*chp) {
124 			case '.':
125 				break;
126 			case 'x':
127 				refh = i;
128 				refv = length;
129 				*chp = '.';
130 				break;
131 			case 'X':
132 				refh = i;
133 				refv = length;
134 			case '@':
135 			case '*':
136 				maxv = length;
137 				if (minv < 0) minv = length;
138 				if (i < minh) minh = i;
139 				if (i > maxh) maxh = i;
140 				break;
141 			default:
142 				error("illegal character '%c' in map.", *chp);
143 		    } /* switch */
144 		} /* for i */
145 		if (fgets(chp, MAXLINE, filep) == NULL)
146 			error("unexpected end of input");
147 	    } /* for length */
148 
149 	    if (stipple) {		/* force whole box if making stipples */
150 		minv = 0;
151 		minh = 0;
152 		maxv = length - 1;
153 		maxh = width - 1;
154 	    }
155 
156 	    if (refv < 0) error("no reference point in glyph %d.", code);
157 	    if (minv < 0) {
158 		minv = maxv = refv;
159 		minh = maxh = refh;
160 	    }
161 	    g[codeindex].up = bound(refv - minv);
162 	    g[codeindex].down = bound(maxv + 1 - refv);
163 	    g[codeindex].right = bound(maxh + 1 - refh);
164 	    g[codeindex].left = bound(refh - minh);
165 #ifdef sun
166 	    g[codeindex].nbytes = (maxv+1-minv) * ((maxh+16-minh) / 16) * 2;
167 #else
168 	    g[codeindex].nbytes = (maxv + 1 - minv) * ((maxh + 8 - minh) >> 3);
169 #endif
170 
171 				/* convert from characters to bits */
172 	    bitp = (glyphs[codeindex] = malloc(g[codeindex].nbytes)) - 1;
173 	    for (i = minv; i <= maxv; i++) {
174 		register int bitwidth;
175 
176 		chp = &charbits[0] + width * i + minh;
177 		bitwidth = 0;
178 		for (j = minh; j <= maxh; j++, chp++) {
179 		    if (--bitwidth < 0) {
180 			*++bitp = '\0';
181 			bitwidth = 7;
182 		    }
183 		    if (*chp != '.') *bitp |= 1 << bitwidth;
184 		}
185 #ifdef sun
186 		if (!((bitp - glyphs[codeindex]) & 1)) *++bitp = '\0';
187 #endif
188 	    } /* for i */
189 	} /* else */
190     } /* while */
191 
192     fileaddr = 0;
193     for (i = 0; i < DIRSIZ; i++) {
194 	if (glyphs[i] == (char *) 0) {
195 	    g[i].nbytes = 0;
196 	} else {
197 	    g[i].addr = fileaddr;
198 	    fileaddr += g[i].nbytes;
199 	    if (g[i].up > head.maxy) head.maxy = g[i].up;
200 	    if (g[i].down > head.xtend) head.xtend = g[i].down;
201 	    if (((int) g[i].left + g[i].right) > head.maxx)
202 		head.maxx = g[i].left + (int) g[i].right;
203 	}
204     }
205     head.size = fileaddr;
206 
207     vwrite((char *) &head, sizeof(head));
208     vwrite((char *) &(g[0]), sizeof(g));
209     for (i = 0; i < DIRSIZ; i++)
210 	if (glyphs[i] != (char *) 0)
211 	    vwrite(glyphs[i], g[i].nbytes);
212     exit(0);
213 }
214 
215 
216 /*----------------------------------------------------------------------------*
217  | Routine:	bound (value)
218  |
219  | Results:	checks to make sure that the dimensions of a glyph fit into
220  |		the vfont format's limitations.  The up, down, right, and left
221  |		fields must fit into a byte!), but can be signed.
222  *----------------------------------------------------------------------------*/
223 
224 bound(i)
225 {
226 	if(i < DIMLIMIT && i >= -DIMLIMIT) return i;
227 	error ("dimension out of range");
228 }
229 
230 
231 /*----------------------------------------------------------------------------*
232  | Routine:	vwrite (buffer, buffer_size)
233  |
234  | Results:	writes out character array "buffer" of size "buffer_size"
235  |		to standard output in small enough chunks that a pipe could
236  |		handle them.
237  |
238  | Bugs:	this routine shouldn't be needed
239  *----------------------------------------------------------------------------*/
240 
241 vwrite(buf, bufsize)
242 char *buf;
243 int bufsize;
244 {
245 	int tsize = 0;
246 
247 	while (bufsize) {
248 		buf += tsize;
249 		tsize = bufsize > BUFSIZ ? BUFSIZ : bufsize;
250 		if ((tsize = write(1, buf, tsize)) < 0) {
251 			perror("ch2vft: write failed");
252 			exit(-1);
253 		}
254 		bufsize -= tsize;
255 	}
256 }
257 
258 
259 /*----------------------------------------------------------------------------*
260  | Routine:	error (format_string, argument1, argument2.... )
261  |
262  | Results:	fprints a message to standard error, then exits with error
263  |		code 1
264  |
265  | Side Efct:	This routine does NOT return
266  *----------------------------------------------------------------------------*/
267 
268 /*VARARGS1*/
269 error(string, a1, a2, a3, a4)
270 char *string;
271 {
272 	fprintf(stderr, "ch2vft: ");
273 	fprintf(stderr, string, a1, a2, a3, a4);
274 	fprintf(stderr, "\n");
275 	exit(1);
276 }
277