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 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*/ 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 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 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