1 /* qms2ch.c 1.1 87/02/05
2 *
3 * Font translation for QMS-style fonts (qms' QUIC format) to character format.
4 *
5 * Use: qms2ch [ -b# ] 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 QUIC format by the
10 * ch2qms program. The "-b" flag sets a baseline unless the font has
11 * one itself. Output goes to stdout.
12 */
13
14 #include <stdio.h>
15 #include <ctype.h>
16
17
18 #define RES 300 /* resolution, in pixels per inch */
19 #define DIRSIZ 256 /* maximum number of characters in font */
20 #define HEADER "^PY^-^F^-^DF"
21 #define BITDIR "/usr/lib/font/devqms/fonts"
22
23
24 char defascii[DIRSIZ]; /* list of ascii characters to print */
25 char *fontdir = BITDIR; /* place to look for fonts */
26 char *header = HEADER; /* string that must start each QUIC font file */
27 char filename[100]; /* input file name put here */
28 char input[100]; /* general-purpose input string */
29 FILE *FID; /* input file number */
30 int height; /* height of every character in the font */
31 int fontid; /* the "font number" */
32 int landscape = 0; /* flag: is this a landscape font? */
33 int insertion = 0; /* flag: is this an addition to a font? */
34 int signed = 0; /* flag: can this font have signed offsets? */
35 int version = 0; /* version code */
36 int baseline = 0; /* baseline of font (if specified) */
37 int printwidth; /* printwidth of each character */
38 /* variables to use when printing characters */
39 int H, W, Hoff, Woff, lbound, rbound;
40
41
main(argc,argv)42 main(argc,argv)
43 int argc;
44 char **argv;
45 {
46 register int i;
47 register int j;
48 register int k;
49 register int Hpoint;
50 register int Wpoint;
51
52
53 if (argc < 2 || argc > 4) {
54 usage:
55 error("usage: %s [ -b# ] filename [ charlist ]", *argv);
56 }
57 ++argv;
58 if (**argv == '-' && (*argv)[1]) {
59 argc--;
60 if (argv[0][1] != 'b')
61 goto usage;
62 baseline = atoi(&(argv[0][2]));
63 argv++;
64 }
65 if (argc == 3) {
66 do
67 defascii[argv[1][0]] = 1;
68 while (*++(argv[1]));
69 } else {
70 for (i = 0; i < DIRSIZ; i++)
71 defascii[i] = 1;
72 }
73
74 sprintf(filename, "%s", *argv);
75 if (filename[0] != '-' || filename[1]) {
76 if ((FID = fopen(filename, "r")) == NULL) {
77 sprintf(filename, "%s/%s", fontdir, *argv);
78 if ((FID = fopen(filename, "r")) == NULL)
79 error("can't find %s", *argv);
80 }
81 } else {
82 FID = stdin;
83 }
84
85 j = strlen(header);
86 (void) getnumber(j);
87 if (strncmp(input, header, j))
88 error("%s, not a QMS Font file.", filename);
89
90 (void) getnumber(6);
91 k = (int) input[0];
92 if (k == 'i' || k == 'I') {
93 fontid = atoi(input + 1);
94 (void) getnumber(1);
95 k = (int) input[0];
96 } else {
97 k = (int) input[5];
98 input[5] = 0;
99 fontid = atoi(input);
100 }
101 switch (k) {
102 case 'y': case 'Y': case 'L': case 'l':
103 landscape = 1;
104 break;
105
106 case 'x': case 'X': case 'P': case 'p':
107 break;
108
109 default:
110 error("font is not portrait or landscape");
111 }
112 version = getnumber(1);
113 (void) getnumber(4);
114 printf("fontheader\nname %s\n", input);
115 printf("version %d\n", version);
116 printf("rot %d\n", landscape ? 1 : 0);
117 printf("cadv %d\n", landscape ? 1 : 2);
118 printf("ladv %d\n", landscape ? 2 : 1);
119 height = getnumber(3);
120 printf("linesp %d.00\n", height);
121 printf("id %d\nres %d\n", fontid, RES);
122 j = getnumber(1);
123 if (isdigit(input[0])) {
124 baseline = j * 100 + getnumber(2);
125 printf("baseline %d.00\n", baseline);
126 (void) getnumber(1);
127 if (landscape)
128 baseline = height - baseline;
129 }
130 if (input[0] != ',') {
131 signed = 1;
132 (void) getnumber(1);
133 if (input[0] != ',')
134 error("error in header, expected \",\"");
135 }
136
137 for (;;) { /* for each character */
138 k = getnumber(1); /* first digit of character number */
139 if (input[0] == '^') {
140 (void) getnumber(1);
141 if (input[0] != 'G')
142 error("expected \"G\"");
143 exit(0);
144 }
145
146 k = k * 16 + getnumber(1); /* second digit of character number */
147 if (!defascii[k]) {
148 do
149 i = getc(FID);
150 while (i != EOF && i != ',');
151 continue; /* ignore characters not asked for */
152 }
153
154 printwidth = getnumber(3);
155 H = getnumber(2);
156 if (input[0] == '^') {
157 switch (input[1]) {
158 case 'M': case 'm':
159 break;
160 case 'R': case 'r':
161 break;
162 }
163 H = getnumber(3);
164 } else {
165 H = H * 10 + getnumber(1);
166 }
167 W = getnumber(3);
168 Hoff = getnumber(3);
169 if (ispunct(input[0])) {
170 if (input[0] == '-')
171 Hoff = 10 * Hoff - getnumber(1);
172 else
173 Hoff = 10 * Hoff + getnumber(1);
174 }
175 Woff = getnumber(3);
176 if (ispunct(input[0])) {
177 if (input[0] == '-')
178 Woff = 10 * Woff - getnumber(1);
179 else
180 Woff = 10 * Woff + getnumber(1);
181 }
182 printf(":%d, width = %d.00\n", k, printwidth);
183
184 if (landscape) {
185 Hpoint = -Hoff;
186 Wpoint = baseline - Woff;
187 } else {
188 Hpoint = baseline - Hoff;
189 Wpoint = -Woff;
190 }
191 if ((lbound = Wpoint) > 0) lbound = 0;
192 if ((rbound = Wpoint + 1) < W) rbound = W;
193
194 for (k = Hpoint; k < 0; k++) {
195 for (i = lbound; i < rbound; i++)
196 printf("%c", k==Hpoint && i==Wpoint ? 'x':'.');
197 putchar ('\n');
198 }
199 for (k = 0; k < H; k++) {
200 /* read in one "line" at a time */
201 (void) getnumber(((W + 15) / 16) * 4);
202
203 for (i = lbound; i < 0; i++)
204 printf("%c", k==Hpoint && i==Wpoint ? 'x':'.');
205 for (i = 0; i < W; i++)
206 printf("%c", k==Hpoint && i==Wpoint ?
207 (fbit(i) ? 'X':'x') : fbit(i) ? '@':'.');
208 while (i < rbound) {
209 printf("%c", k==Hpoint && i==Wpoint ? 'x':'.');
210 i++;
211 }
212 putchar ('\n');
213 }
214 while (k <= Hpoint) {
215 for (i = lbound; i < rbound; i++)
216 printf("%c", k==Hpoint && i==Wpoint ? 'x':'.');
217 putchar ('\n');
218 k++;
219 }
220 putchar ('\n');
221 (void) getnumber(1);
222 if (input[0] != ',')
223 error("expected \",\"");
224 }
225 }
226
227
228 /*----------------------------------------------------------------------------*
229 | Routine: error (format_string, argument1, argument2.... )
230 |
231 | Results: fprints a message to standard error, then exits with error
232 | code 1
233 |
234 | Side Efct: This routine does NOT return
235 *----------------------------------------------------------------------------*/
236 /*VARARGS1*/
error(string,a1,a2,a3,a4)237 error(string, a1, a2, a3, a4)
238 char *string;
239 {
240 fprintf(stderr, "qms2ch: ");
241 fprintf(stderr, string, a1, a2, a3, a4);
242 fprintf(stderr, "\n");
243 exit(1);
244 }
245
246
247 /*----------------------------------------------------------------------------*
248 | Routine: fbit (row)
249 |
250 | Results: returns true (non-0) or false (0) to signify whether the bit
251 | in "row" of the current input line (hex digits) is on or off.
252 |
253 | Side Efct: exits the program if the character in the line isn't valid hex
254 *----------------------------------------------------------------------------*/
255
fbit(row)256 fbit(row)
257 int row;
258 {
259 register int piece = row & 3;
260
261 switch (input[row / 4]) {
262 case '0': return 0;
263 case '1': return (piece == 3);
264 case '2': return (piece == 2);
265 case '3': return (piece > 1);
266 case '4': return (piece == 1);
267 case '5': return (piece == 1 || piece == 3);
268 case '6': return (piece == 1 || piece == 2);
269 case '7': return (piece);
270 case '8': return (!piece);
271 case '9': return (piece == 3 || !piece);
272 case 'A': case 'a': return (piece == 2 || !piece);
273 case 'B': case 'b': return (piece != 1);
274 case 'C': case 'c': return (piece < 2);
275 case 'D': case 'd': return (piece != 2);
276 case 'E': case 'e': return (piece != 3);
277 case 'F': case 'f': return 1;
278
279 default: error("expected HEX digit");
280 }
281 }
282
283
284 /*----------------------------------------------------------------------------*
285 | Routine: getnumber (digits)
286 |
287 | Results: read a string of "digits" length from the input file "FID"
288 | and return the decimal value of the string. If the string
289 | is one character long, it may be interpreted as a hex number.
290 | In any case the null-terminated string is returned globally
291 | to "input".
292 |
293 | Side Efct: This routine SKIPS WHITE SPACE, and exits upon error.
294 *----------------------------------------------------------------------------*/
295
296 int
getnumber(digits)297 getnumber(digits)
298 int digits;
299 {
300 register int i;
301 register int j;
302
303 for (i = 0; i < digits; ) {
304 if ((j = getc(FID)) == EOF)
305 error ("unexpected end of input");
306 if (!isspace(input[i] = (char) j))
307 i++;
308 }
309 input[digits] = (char) 0;
310 if (digits > 1) {
311 return (atoi(input));
312 } else switch (input[0]) {
313 case '0': return 0;
314 case '1': return 1;
315 case '2': return 2;
316 case '3': return 3;
317 case '4': return 4;
318 case '5': return 5;
319 case '6': return 6;
320 case '7': return 7;
321 case '8': return 8;
322 case '9': return 9;
323 case 'A': case 'a': return 10;
324 case 'B': case 'b': return 11;
325 case 'C': case 'c': return 12;
326 case 'D': case 'd': return 13;
327 case 'E': case 'e': return 14;
328 case 'F': case 'f': return 15;
329
330 default: return 0;
331 }
332 }
333