1 /*	ch2x.c	1.1	87/02/05
2  *
3  * Font translation to X format from character format.
4  *
5  *	Use:	ch2x  [ -i  -s ]  charfile  >  xfontfile
6  *
7  *		Takes input from charfile (which must be in the format written
8  *	by one of the xxx2ch programs), converts to X format and writes it
9  *	to stdout.  If charfile is missing, stdin is read.  The -i flag tells
10  *	ch2x 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.  Unlike other conversion programs, white space around a glyph
13  *	is preserved.  Therefore, the -s option is ignored.
14  */
15 
16 #include <stdio.h>
17 #include "xfont.h"
18 
19 
20 #define RES		75	/* for xfont, resolution is 75 */
21 #define MAXLINE		300
22 #define	GLYPHSPACE	(MAXLINE * MAXLINE / 8)
23 #define DIRSIZ		256	/* maximum # of entries */
24 
25 
26 char *	malloc();
27 char *	index();
28 
29 struct FontData	FH;		/* font file header */
30 struct GlyphData {
31 	short up;
32 	short down;
33 	short left;
34 	short right;
35 	short nbytes;
36 	short width;
37 	char *ptr;
38 } g[DIRSIZ];			/* table of glyph definitions */
39 short	leftarea[DIRSIZ];
40 char 	bitmap[GLYPHSPACE];
41 char *	newbitmap;
42 
43 int	code;
44 int	printwidth, width, length, refv, refh;
45 int	totalwidth, maxleft, maxup, maxdown;
46 
47 int	ignorecode = 0;
48 FILE *	filep;
49 char	ibuff[MAXLINE];
50 
51 
52 main(argc,argv)
53 int argc;
54 char **argv;
55 {
56     register int i;
57     register int j;
58     register int codeindex;
59     register char *chp;
60     register char *bitp;
61     register int bit;
62     float par;
63 
64 
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 		break;
73 	default:
74 		error("%s, unknown option flag", argv[1]);
75 	}
76 	argc--; argv++;
77     }
78 
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     totalwidth = 0;
86     maxleft = 0;
87     maxup = 0;
88     maxdown = 0;
89     FH.fixedWidth = -1;
90     for (i = 0; i < DIRSIZ; g[i++].ptr = (char *) 0);
91 
92     if (fgets(ibuff, MAXLINE, filep) == NULL || strcmp(ibuff, "fontheader\n"))
93 	error("not a character font file");
94 
95     while (fgets(ibuff, MAXLINE, filep) != NULL) {
96 	if (index(ibuff, '\n') == NULL)
97 	    error("input line too long");
98 
99 	if (ibuff[0] == ':') {
100 	    if (sscanf (ibuff, ":%d, width = %f", &code, &par) != 2)
101 		error("bad glyph header \"%s\"", ibuff);
102 	    if (ignorecode) codeindex++; else codeindex = code;
103 	    if (codeindex < 0 || codeindex >= DIRSIZ)
104 		error("code (%d) out of range", codeindex);
105 	    printwidth = par + 0.5;
106 
107 	    chp = &ibuff[0];
108 	    bitp = &bitmap[-1];
109 	    if (fgets(chp, MAXLINE, filep) == NULL)
110 		error("unexpected end of input");
111 	    width = strlen(chp) - 1;
112 	    refv = -1;
113 
114 	    for (length = 0; *chp != '\n'; length++) {
115 		bit = 0x100;
116 		for (i = 0; i < width; i++, chp++) {
117 		    if (bit == 0x100) {
118 			if (++bitp >= &bitmap[GLYPHSPACE])
119 			    error ("out of glyph space");
120 			*bitp = 0;
121 			bit = 1;
122 		    }
123 		    switch (*chp) {
124 			case '.':
125 				break;
126 			case 'x':
127 				refh = i;
128 				refv = length;
129 				break;
130 			case 'X':
131 				refh = i;
132 				refv = length;
133 			case '@':
134 			case '*':
135 				*bitp |= bit;
136 				break;
137 			default:
138 				error("illegal character '%c' in map.", *chp);
139 		    } /* switch */
140 		    bit <<= 1;
141 		} /* for i */
142 		chp = &ibuff[0];
143 		if (fgets(chp, MAXLINE, filep) == NULL)
144 			error("unexpected end of input");
145 	    } /* for length */
146 
147 	    if (refv < 0) error("no reference point in glyph %d.", code);
148 
149 	    g[codeindex].up = refv;
150 	    g[codeindex].down = length - refv;
151 	    g[codeindex].right = width - refh;
152 	    if (g[codeindex].right > printwidth)
153 		printwidth = g[codeindex].right;
154 	    g[codeindex].left = refh;
155 	    g[codeindex].nbytes = bitp - bitmap + 1;
156 	    g[codeindex].width = printwidth;
157 	    totalwidth += printwidth;
158 	    if (FH.fixedWidth == -1)
159 		FH.fixedWidth = printwidth;
160 	    if (FH.fixedWidth != printwidth)
161 		FH.fixedWidth = 0;
162 	    if (g[codeindex].left > maxleft) maxleft = g[codeindex].left;
163 	    if (g[codeindex].up > maxup) maxup = g[codeindex].up;
164 	    if (g[codeindex].down > maxdown) maxdown = g[codeindex].down;
165 
166 				/* copy the bits to private place */
167 	    if ((g[codeindex].ptr = malloc(g[codeindex].nbytes)) == NULL)
168 		error("out of memory reading in file");
169 	    bcopy(bitmap, g[codeindex].ptr, g[codeindex].nbytes);
170 	} /* if ibuff == : */
171     } /* while not EOF */
172 
173     if (totalwidth == 0)
174 	error("empty font");
175 
176     /*
177      * Fill in the "fontData" header for this font.  fixedWidth is already set.
178      */
179     FH.waste = 0;
180     FH.bitsPerPixel = 1;
181     FH.spaceIndex = 32;			/* we can only guess */
182     for (i = 0; g[i].ptr == NULL; i++)
183 	;
184     FH.firstChar = i;
185     for (i = DIRSIZ - 1; g[i].ptr == NULL; i--)
186 	;
187     FH.lastChar = i;
188     FH.bmHeight = maxup + maxdown;
189     FH.baseline = maxup + 1;
190     FH.leftArray = sizeof (FH);
191     FH.bitmapPtr = FH.leftArray + (FH.lastChar-FH.firstChar+2) * sizeof(short);
192 
193     /*
194      * calculate "leftarea" - the pointers for each glyph into the bitmap
195      */
196     leftarea[FH.firstChar] = 0;
197     for (i = FH.firstChar; i <= FH.lastChar; i++) {
198 	if (g[i].ptr == NULL) {
199 	    FH.fixedWidth = 0;
200 	    leftarea[i + 1] = leftarea[i];
201 	} else {
202 	    leftarea[i + 1] = leftarea[i] + g[i].width + maxleft;
203 	    totalwidth += maxleft;
204 	}
205     }
206     FH.bmWidth = totalwidth;
207     width = ((totalwidth + 15) >> 3) & ~1;
208     newbitmap = bitmap;
209     if (width > GLYPHSPACE)
210 	if ((newbitmap = malloc(width)) == NULL)
211 	    error("out of memory writing file");
212 
213     vwrite(&FH, sizeof(FH));
214     vwrite(&leftarea[FH.firstChar],(FH.lastChar-FH.firstChar+2)*sizeof(short));
215     /*
216      * Calculate and write out the "strike" bitmap
217      */
218     for (length = 0; length < FH.bmHeight; length++) {
219 	bitp = newbitmap;
220 	*bitp = 0;
221 	i = 1;
222 	for (codeindex = FH.firstChar; codeindex <= FH.lastChar; codeindex++) {
223 	    if (g[codeindex].ptr != NULL) {
224 		for (j = -maxleft; j < g[codeindex].width; j++) {
225 		    if (bitset(&g[codeindex], j, maxup)) {
226 			*bitp |= i;
227 		    }
228 		    i <<= 1;
229 		    if (i == 0x100) {
230 			*++bitp = 0;
231 			i = 1;
232 		    }
233 		}
234 	    }
235 	}
236 	vwrite(newbitmap, width);
237 	maxup--;
238     }
239     exit(0);
240 }
241 
242 
243 /*----------------------------------------------------------------------------*
244  | Routine:	vwrite (buffer, buffer_size)
245  |
246  | Results:	writes out character array "buffer" of size "buffer_size"
247  |		in sizes that "write" can handle
248  *----------------------------------------------------------------------------*/
249 
250 vwrite(buf, bufsize)
251 char *buf;
252 int bufsize;
253 {
254 	int tsize = 0;
255 
256 	while (bufsize) {
257 		buf += tsize;
258 		if ((tsize = write(1, buf, bufsize)) < 0) {
259 			perror("ch2x: write failed");
260 			exit(-1);
261 		}
262 		bufsize -= tsize;
263 	}
264 }
265 
266 
267 /*----------------------------------------------------------------------------*
268  | Routine:	bitset (GlyphData_pointer, x_position, y_position)
269  |
270  | Results:	Given a Glyph definition and an x,y position (relative to the
271  |		reference point of the glyph) bitset returns non-zero if the
272  |		glyph has a pixel set at that point.
273  *----------------------------------------------------------------------------*/
274 
275 /*VARARGS1*/
276 bitset(g, x, y)
277 register struct GlyphData *g;
278 register int x;
279 register int y;
280 {
281 	register char *p;
282 
283 	x += g->left;
284 	y = g->up - y;
285 	if (x < 0 || y < 0 || x >= (g->left+g->right) || y >= (g->up+g->down))
286 		return(0);
287 	p = g->ptr + (x >> 3) + y * ((g->left + g->right + 7) >> 3);
288 	return( *p & (1 << (x&7)) );
289 }
290 
291 
292 /*----------------------------------------------------------------------------*
293  | Routine:	error (format_string, argument1, argument2.... )
294  |
295  | Results:	fprints a message to standard error, then exits with error
296  |		code 1
297  |
298  | Side Efct:	This routine does NOT return
299  *----------------------------------------------------------------------------*/
300 
301 /*VARARGS1*/
302 error(string, a1, a2, a3, a4)
303 char *string;
304 {
305 	fprintf(stderr, "ch2x: ");
306 	fprintf(stderr, string, a1, a2, a3, a4);
307 	fprintf(stderr, "\n");
308 	exit(1);
309 }
310