1 /*	ch2rst.c	1.7	86/03/04
2  *
3  * Font translation to Imagen-style fonts (RST format) from character format.
4  *
5  *	Use:	ch2rst  [ -i  -s ]  charfile  > rstfile
6  *
7  *		Takes input from charfile (which must be in the format written
8  *	by one of the xxx2ch programs), converts to rst format and writes to
9  *	stdout.  If charfile is missing, stdin is read.  The -i flag tells
10  *	ch2rst 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 ch2rst to NOT trim off any white space in
13  *	the glyph map.  This is usefull to make stipples of fixed size.
14  */
15 
16 #include <stdio.h>
17 #include "rst.h"
18 
19 
20 #define PREAMBLE	44			/* size of preamble */
21 #define STRINGS		2			/* length of strings at pre. */
22 #define STARTGLYPH	PREAMBLE + STRINGS
23 #define MAXLINE		300
24 #define GLYPHSPACE	(MAXLINE * MAXLINE)
25 #define wr1(x)		putchar(x)
26 
27 
28 char *	malloc();
29 
30 glyph_dir g[DIRSIZ];		/* directory of glyph definitions */
31 preamble p;			/* set of variables for preamble */
32 double widthtofix;		/* fix conversion factor */
33 double wordsptemp;		/* holds wordsp "fix" `til res. is known */
34 double linesptemp;		/* holds linesp "fix" `til res. is known */
35 
36 int	code;			/* read in code for a glyph */
37 int	width, length;		/* width and length of read-in matrix */
38 int	maxv, minv, maxh, minh;	/* extent of "blackness" in glyph */
39 int	refv, refh;		/* reference point in matrix */
40 int	bitwidth;
41 
42 int	ignorecode = 0;		/* flag: ignore the code number; successive */
43 int	stipple = 0;		/* flag: don't eliminate white-space */
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     while (argc > 1 && argv[1][0] == '-') {
63 	switch(argv[1][1]) {
64 	case 'i':
65 		ignorecode = 1;
66 		break;
67 
68 	case 's':
69 		stipple = 1;
70 		break;
71 	default:
72 		error("%s, unknown option flag", argv[1]);
73 	}
74 	argc--; argv++;
75     }
76 
77     if (argc > 2)
78 	error("too many arguments");
79     if (argc == 2) {
80 	if ((filep = fopen (argv[1], "r")) == NULL)
81 	    error("can't open file \"%s\"", argv[1]);
82     } else filep = stdin;
83 
84     codeindex = 0;
85     for (i = 0; i < DIRSIZ; glyphs[i++] = (char *) 0);
86 
87     fgets(ibuff, MAXLINE, filep);
88     if (strcmp(ibuff, "fontheader\n"))
89 	error("not a character font file");
90 
91     while (fgets(ibuff, MAXLINE, filep) != NULL) {
92 	if (index(ibuff, '\n') == 0)
93 	    error("input line too long");
94 
95 	if (ibuff[0] != ':') {
96 	    sscanf (ibuff, "%s %f", ebuff, &par);
97 	    if (strcmp(ebuff, "size") == 0) p.p_size = par + 0.5;
98 	    else if (strcmp(ebuff, "version") == 0) {
99 		if (p.p_version = par + 0.5)
100 		    error("wrong version (%d) for Font file.", p.p_version);
101 	    } else if (strcmp(ebuff, "mag") == 0) p.p_mag = par + 0.5;
102 	    else if (strcmp(ebuff, "desiz") == 0) p.p_desiz = par / FIX + 0.5;
103 	    else if (strcmp(ebuff, "linesp") == 0) linesptemp = par;
104 	    else if (strcmp(ebuff, "wordsp") == 0) wordsptemp = par;
105 	    else if (strcmp(ebuff, "rot") == 0) p.p_rot = par + 0.5;
106 	    else if (strcmp(ebuff, "cadv") == 0) p.p_cadv = par + 0.5;
107 	    else if (strcmp(ebuff, "ladv") == 0) p.p_ladv = par + 0.5;
108 	    else if (strcmp(ebuff, "id") == 0) p.p_id = par + 0.5;
109 	    else if (strcmp(ebuff, "res") == 0) p.p_res = par + 0.5;
110 		/* ignore unrecognized fields */
111 	} else {
112 			/* set up for real resolution of font file */
113 	    if (p.p_mag)
114 		widthtofix = 1000.0 / (FIXIN * p.p_res * p.p_mag);
115 	    else
116 		widthtofix = (1.0 / (FIXIN * p.p_res));
117 	    p.p_wordsp = wordsptemp * widthtofix + 0.5;
118 	    p.p_linesp = linesptemp * widthtofix + 0.5;
119 
120 	    if (sscanf (ibuff, ":%d, width = %f", &code, &par) != 2)
121 		error("bad glyph header, %s", ibuff);
122 	    if (ignorecode) codeindex++; else codeindex = code;
123 	    g[codeindex].g_pwidth = par * widthtofix + 0.5;
124 
125 	    chp = &charbits[0];
126 	    if (fgets(chp, MAXLINE, filep) == NULL)
127 		error("unexpected end of input");
128 	    width = strlen(chp) - 1;
129 	    minh = width;
130 	    maxh = 0;
131 	    refv = minv = -1;
132 
133 	    for (length = 0; *chp != '\n'; length++) {
134 		if ((length + 1) * width > GLYPHSPACE)
135 		    error ("out of glyph space");
136 		for (i = 0; i < width; i++, chp++) {
137 		    switch (*chp) {
138 			case '.':
139 				break;
140 			case 'x':
141 				if (refv != -1)
142 				 error("two reference points in glyph %d",code);
143 				refh = i;
144 				refv = length;
145 				*chp = '.';
146 				break;
147 			case 'X':
148 				if (refv != -1)
149 				 error("two reference points in glyph %d",code);
150 				refh = i;
151 				refv = length;
152 			case '@':
153 			case '*':
154 				maxv = length;
155 				if (minv < 0) minv = length;
156 				if (i < minh) minh = i;
157 				if (i > maxh) maxh = i;
158 				break;
159 			default:
160 				error("illegal character '%c' in map.", *chp);
161 		    } /* switch */
162 		} /* for i */
163 		if (*chp != '\n')
164 		    error("not all lines equal length in glyph %d", code);
165 		if (fgets(chp, MAXLINE, filep) == NULL)
166 			error("unexpected end of input");
167 	    } /* for length */
168 
169 	    if (stipple) {		/* use the whole box to make a */
170 		minv = 0;		/* stipple pattern. */
171 		minh = 0;
172 		maxv = length - 1;
173 		maxh = width - 1;
174 	    }
175 
176 	    if (refv < 0) error("no reference point in glyph %d.", code);
177 	    if (minv < 0) {
178 		minv = maxv = refv;
179 		minh = maxh = refh;
180 	    }
181 	    g[codeindex].g_height = maxv + 1 - minv;
182 	    g[codeindex].g_width = maxh + 1 - minh;
183 	    g[codeindex].g_up = refv - minv;
184 	    g[codeindex].g_left = refh - minh;
185 	    g[codeindex].g_bitp =
186 		g[codeindex].g_height * ((g[codeindex].g_width + 7) / 8);
187 
188 	    bitp = (glyphs[codeindex] = malloc(g[codeindex].g_bitp)) - 1;
189 	    if (!glyphs[codeindex])
190 		error("out of memory");
191 	    for (i = minv; i <= maxv; i++) {
192 		chp = &charbits[0] + width * i + minh;
193 		bitwidth = 0;
194 		for (j = minh; j <= maxh; j++, chp++) {
195 		    if (--bitwidth < 0) {
196 			*++bitp = '\0';
197 			bitwidth = 7;
198 		    }
199 		    if (*chp != '.') *bitp |= 1 << bitwidth;
200 		}
201 	    } /* for i */
202 	} /* else */
203     } /* while */
204 
205     if (ignorecode) {
206 	p.p_last = codeindex - 1;
207 	p.p_first = 0;
208     } else {
209 	for (i = DIRSIZ - 1; glyphs[i] == (char *) 0; i--);
210 	p.p_last = i;
211 	for (i = 0; glyphs[i] == (char *) 0; i++);
212 	p.p_first = i;
213     }
214     bitwidth = STARTGLYPH + 15 * (1 + p.p_last - p.p_first);
215 
216     printf("Rast UCB");
217     wr2(p.p_size);	 wr1(p.p_version);	wr3(STARTGLYPH);
218     wr2(p.p_first);	 wr2(p.p_last);		wr4(p.p_mag);
219     wr4(p.p_desiz);	 wr4(p.p_linesp);	wr4(p.p_wordsp);
220     wr2(p.p_rot);	 wr1(p.p_cadv);		wr1(p.p_ladv);
221     wr4(p.p_id);	 wr2(p.p_res);
222     for (i = 0; i < STRINGS; i++) putchar('\0');
223 
224     for (i = p.p_first; i <= p.p_last; i++) {
225 	if (glyphs[i] == (char *) 0) {
226 	    for (j = 0; j < 15; j++) putchar('\0');
227 	} else {
228 	    wr2(g[i].g_height);
229 	    wr2(g[i].g_width);
230 	    wr2(g[i].g_up);
231 	    wr2(g[i].g_left);
232 	    wr4(g[i].g_pwidth);
233 	    wr3(bitwidth);
234 	    bitwidth += g[i].g_bitp;
235 	}
236     } /* for i */
237     fflush(stdout);
238 
239     for (i = p.p_first; i <= p.p_last; i++)
240 	if (glyphs[i] != (char *) 0)
241 	    vwrite(glyphs[i], g[i].g_bitp);
242     exit(0);
243 }
244 
245 
246 /*----------------------------------------------------------------------------*
247  | Routine:	vwrite (buffer, buffer_size)
248  |
249  | Results:	writes out character array "buffer" of size "buffer_size"
250  |		to standard output in small enough chunks that a pipe could
251  |		handle them.
252  |
253  | Bugs:	this routine shouldn't be needed
254  *----------------------------------------------------------------------------*/
255 
256 vwrite(buf, bufsize)
257 char *buf;
258 int bufsize;
259 {
260 	int tsize = 0;
261 
262 	while (bufsize) {
263 		buf += tsize;
264 		tsize = bufsize > BUFSIZ ? BUFSIZ : bufsize;
265 		if ((tsize = write(1, buf, tsize)) < 0) {
266 			perror("ch2rst: write failed");
267 			exit(-1);
268 		}
269 		bufsize -= tsize;
270 	}
271 }
272 
273 
274 /*----------------------------------------------------------------------------*
275  | Routine:	error (format_string, argument1, argument2.... )
276  |
277  | Results:	fprints a message to standard error, then exits with error
278  |		code 1
279  |
280  | Side Efct:	This routine does NOT return
281  *----------------------------------------------------------------------------*/
282 
283 /*VARARGS1*/
284 error(string, a1, a2, a3, a4)
285 char *string;
286 {
287 	fprintf(stderr, "ch2rst: ");
288 	fprintf(stderr, string, a1, a2, a3, a4);
289 	fprintf(stderr, "\n");
290 	exit(1);
291 }
292 
293 
294 /*----------------------------------------------------------------------------*
295  | Routine:	wr2, wr3, wr4 (and wr1)
296  |
297  | Results:	writes out 2, 3, or 4 byte integers in RST byte order, using
298  |		the wr1() routine, which writes one byte to standard output.
299  *----------------------------------------------------------------------------*/
300 
301 wr2(i)
302 unsigned int i;
303 {
304     wr1((i >> 8) & 255);
305     wr1(i & 255);
306 }
307 
308 wr3(i)
309 unsigned int i;
310 {
311     wr1((i >> 16) & 255);
312     wr1(( i >> 8) & 255);
313     wr1(i & 255);
314 }
315 
316 wr4(i)
317 unsigned int i;
318 {
319     wr1((i >> 24) & 255);
320     wr1((i >> 16) & 255);
321     wr1((i >> 8) & 255);
322     wr1(i & 255);
323 }
324