1 /*	x2ch.c	1.1	87/02/05
2  *
3  * Font translation for X font-style fonts to character format.
4  *
5  *	Use:  x2ch  [ -p# ] fontfile  [ character_list ]
6  *
7  *		Reads "fontfile" from current directory (or if not found,
8  *	from BITDIR defined below) and converts it to a character font format
9  *	editable by real people, and convertable BACK to X format by the
10  *	ch2x program.  The -p option specifies the "point size" of the font.
11  *	If no "-p#" is specified, the pointsize is 10.  Output goes to stdout.
12  */
13 /* #define DEBUG   	/* if defined, statistics are printed to stderr */
14 
15 #include <stdio.h>
16 #include "xfont.h"
17 
18 
19 #define	DIRSIZ	256
20 #define BITDIR		"/usr/new/lib/X/font"
21 
22 
23 struct FontData FH;
24 #define	first	FH.firstChar
25 #define	last	FH.lastChar
26 short	bitmapindex[DIRSIZ + 1];/* bit offsets in bitmap */
27 short	widths[DIRSIZ + 1];	/* widths calculated from but offsets */
28 char	*charbits;		/* pointer to start of bitmap */
29 char	**lineptr;		/* pointers to start of each line of bitmap */
30 int	pointsize = 10;		/* can only be changed from command line */
31 int	tmp;			/* used for various short-lived things */
32 int	*bitcount;		/* place to hold count of bits on a particular
33 				   line in bitmap - used to find the baseline */
34 
35 char	IName[100];			/* input file name building place */
36 unsigned char	defascii[DIRSIZ];	/* default characters to print */
37 unsigned char	*charswanted = defascii;
38 
39 
40 main(argc, argv)
41 int argc;
42 char **argv;
43 {
44 	register int i;
45 	register int j;
46 	int FID;
47 
48 	if (argc < 2 || argc > 4) {
49     usage:
50 		error("usage: %s [ -p# ] filename [ character-list ]", argv[0]);
51 	}
52 	if (argv[1][0] == '-') {
53 		argv++;
54 		if (argv[0][1] != 'p')
55 			goto usage;
56 		pointsize = atoi(&(argv[0][2]));
57 	}
58 	for (i = 0; i < DIRSIZ; i++) {
59 		bitmapindex[i] = 0;
60 		widths[i] = 0;
61 		defascii[i] = i;
62 	}
63 	if (argc == 3)
64 		charswanted = (unsigned char *) argv[2];
65 
66 	/*
67 	 * find font in BITDIR or current directory, also trying to
68 	 * tack on the ".onx" extension onto the filename
69 	 */
70 	++argv;
71 	sprintf(IName, "%s/%s.onx", BITDIR, *argv);
72 	if ((FID = open(*argv, 0)) < 0) {
73 		if ((FID = open(IName, 0)) < 0) {
74 			sprintf(IName, "%s.onx", *argv);
75 			if ((FID = open(IName, 0)) < 0) {
76 				sprintf(IName, "%s/%s", BITDIR, *argv);
77 				if ((FID = open(IName, 0)) < 0)
78 					error("Can't find %s", *argv);
79 			}
80 		}
81 	}
82 
83 	if (read(FID, &FH, sizeof FH) != sizeof FH)
84 		error("no header in Font file.");
85 	if (first < 0 || last >= DIRSIZ || last <= first)
86 		error("font boundaries (%d,%d) out of range", first, last);
87 	if (FH.bmWidth <= 0 || FH.bmWidth >= 20000 ||
88 			FH.bmHeight <= 0 || FH.bmHeight >= 20000)
89 		error("dimensions (%d,%d) out of range",FH.bmWidth,FH.bmHeight);
90 	i = (((FH.bmWidth + 15) >> 3) &~ 1) * FH.bmHeight;
91 	charbits = (char *) malloc(i);
92 
93 #ifdef DEBUG
94 	fprintf(stderr,"Bit Map Ptr = %d\nBitMap Width = %d\nBit Map Height = %d\nBitsPerPixel = %d\nFirst Character = %d\nLast Character = %d\nLeft Array = %d\nBaseLine = %d\nSpace Index = %d\nFixed Width = %d\nbit map size = %d\n", FH.bitmapPtr, FH.bmWidth, FH.bmHeight, FH.bitsPerPixel, FH.firstChar, FH.lastChar, FH.leftArray, FH.baseline, FH.spaceIndex, FH.fixedWidth, i);
95 #endif
96 
97 	lseek (FID, (long) FH.bitmapPtr, 0);
98 	if (read(FID, charbits, i) != i)
99 		error("bit map (%d chars) not in Font file", i);
100 
101 	if (FH.fixedWidth == 0) {
102 		i = (last - first + 2) * sizeof (short);
103 #ifdef DEBUG
104 		fprintf(stderr, "width array size = %d\n", i);
105 #endif
106 		lseek (FID, (long) FH.leftArray, 0);
107 		if (read(FID, &bitmapindex[first], i) != i)
108 			error("width map not in Font file");
109 	} else {
110 		for (i = first + 1; i <= last + 1; i++)
111 			bitmapindex[i] = bitmapindex[i - 1] + FH.fixedWidth;
112 	}
113 	/*
114 	 * figure out character widths from "leftarray"
115 	 */
116 #ifdef DEBUG
117 	fprintf(stderr,"left,widths:\n");
118 #endif
119 	for (i = first; i <= last; i++) {
120 		if ((widths[i] = bitmapindex[i + 1] - bitmapindex[i]) < 0)
121 			error ("inconsistent width table");
122 #ifdef DEBUG
123 		fprintf(stderr,"%03d:%5d,%6d\n", i, bitmapindex[i], widths[i]);
124 #endif
125 	}
126 	lineptr = (char **) malloc((FH.bmHeight + 2) * sizeof (char *));
127 	j = ((FH.bmWidth + 15) >> 3) &~ 1;
128 	lineptr[0] = charbits;
129 	for (i = 1; i <= FH.bmHeight; i++) {
130 		lineptr[i] = lineptr[i - 1] + j;
131 	}
132 
133 	/*
134 	 * If not given a baseline, try to figure one out by counting the
135 	 * bits in a given row.  When the number falls suddenly, that's the
136 	 * baseline.  This is not guaranteed to work.
137 	 */
138 	if (--FH.baseline < 0) {
139 		tmp = 0;
140 		bitcount = (int *) malloc((FH.bmHeight + 2) * sizeof (int));
141 		for (i = 0; i < FH.bmHeight; i++) {
142 			bitcount[i] = 0;
143 			for (j = 0; j < FH.bmWidth; j++) {
144 				if (bitset(lineptr[i], j))
145 					bitcount[i]++;
146 			}
147 			tmp += bitcount[i];
148 #ifdef DEBUG
149 			fprintf(stderr, "bitcount[%d] == %d\n", i, bitcount[i]);
150 #endif
151 		}
152 		tmp /= FH.bmHeight + 1;
153 #ifdef DEBUG
154 		fprintf(stderr, "average == %d\n", tmp);
155 #endif
156 		for (i = 1; i < FH.bmHeight; i++) {
157 			if (bitcount[i-1] > tmp && bitcount[i] < (tmp >> 1))
158 				FH.baseline = i - 1;
159 		}
160 		if (FH.baseline < 0)
161 			FH.baseline = 0;
162 	}
163 
164 	printf("fontheader\ndesiz %d\nmag 1000\n", pointsize);
165 	printf("rot 0\ncadv 0\nladv 1\nid 0\nres 75\n");
166 
167 	for (i = 0; i < DIRSIZ; i++) {
168 		j = charswanted[i];
169 		if (i > 0 && j == 0)
170 			break;
171 		if (widths[j]) {
172 			register int k;
173 			register int l;
174 
175 			printf(":%d, width = %d.00\n", j, widths[j]);
176 
177 			for (k = 0; k < FH.bmHeight; k++) {
178 			    for (l = 0; l < widths[j]; l++) {
179 				if (bitset(lineptr[k], bitmapindex[j]+l)) {
180 					if (l == 0 && k == FH.baseline)
181 						putchar('X');
182 					else
183 						putchar('@');
184 				} else {
185 					if (l == 0 && k == FH.baseline)
186 						putchar('x');
187 					else
188 						putchar('.');
189 				}
190 			    }
191 			    putchar('\n');
192 			}
193 
194 			putchar('\n');
195 		}
196 	}
197 	exit(0);
198 }
199 
200 
201 /*----------------------------------------------------------------------------*
202  | Routine:	error (format_string, argument1, argument2.... )
203  |
204  | Results:	fprints a message to standard error, then exits with error
205  |		code 1
206  |
207  | Side Efct:	This routine does NOT return
208  *----------------------------------------------------------------------------*/
209 
210 /*VARARGS1*/
211 error(string, a1, a2, a3, a4)
212 char *string;
213 {
214 	fprintf(stderr, "x2ch: ");
215 	fprintf(stderr, string, a1, a2, a3, a4);
216 	fprintf(stderr, "\n");
217 	exit(1);
218 }
219 
220 
221 /*----------------------------------------------------------------------------*
222  | Routine:	bitset (bitstream pointer, bit number)
223  |
224  | Results:	returns nonzero if a bit is set in a supplied bit stream.
225  |		No range checking is done on anything.  Bit order is least
226  |		significant to most significant.
227  *----------------------------------------------------------------------------*/
228 
229 bitset(stream, bit)
230 char *stream;
231 register int bit;
232 {
233 	register char *p;
234 
235 	p = stream + (bit >> 3);
236 	return ((*p) & (1 << (bit & 7)));
237 }
238