xref: /plan9/sys/src/cmd/postscript/misc/ibmfont.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 /*
2  *
3  * Program that converts IBM font files to a format that works on Unix systems.
4  * Essentially all the information needed came from the Adobe paper "Supporting
5  * Downloadable PostScript Fonts". To use the program type,
6  *
7  *	ibmfont font.ibm >font.unix
8  *
9  * where font.ibm is the font file, exactly as it came over from an IBM PC,
10  * and font.unix is equivalent host resident font file usable on Unix systems.
11  *
12  */
13 
14 #include <stdio.h>
15 #include <signal.h>
16 
17 #define OFF		0
18 #define ON		1
19 
20 #define NON_FATAL	0
21 #define FATAL		1
22 
23 #define FALSE		0
24 #define TRUE		1
25 
26 char	**argv;
27 int	argc;
28 
29 char	*prog_name;
30 
31 int	x_stat;
32 int	debug = OFF;
33 int	ignore = OFF;
34 
35 FILE	*fp_in = stdin;
36 FILE	*fp_out = stdout;
37 
38 /*****************************************************************************/
39 
main(agc,agv)40 main(agc, agv)
41 
42     int		agc;
43     char	*agv[];
44 
45 {
46 
47 /*
48  *
49  * IBM PC to Unix font converter.
50  *
51  */
52 
53     argc = agc;
54     argv = agv;
55     prog_name = argv[0];
56 
57     options();
58     arguments();
59     exit(x_stat);
60 
61 }   /* End of main */
62 
63 /*****************************************************************************/
64 
options()65 options()
66 
67 {
68 
69     int		ch;
70     char	*names = "DI";
71 
72     extern char	*optarg;
73     extern int	optind;
74 
75 /*
76  *
77  * Command line options.
78  *
79  */
80 
81     while ( (ch = getopt(argc, argv, names)) != EOF ) {
82 	switch ( ch ) {
83 	    case 'D':			/* debug flag */
84 		    debug = ON;
85 		    break;
86 
87 	    case 'I':			/* ignore FATAL errors */
88 		    ignore = ON;
89 		    break;
90 
91 	    case '?':			/* don't understand the option */
92 		    error(FATAL, "");
93 		    break;
94 
95 	    default:			/* don't know what to do for ch */
96 		    error(FATAL, "missing case for option %c\n", ch);
97 		    break;
98 	}   /* End switch */
99     }   /* End while */
100 
101     argc -= optind;
102     argv += optind;
103 
104 }   /* End of options */
105 
106 /*****************************************************************************/
107 
arguments()108 arguments()
109 
110 {
111 
112 /*
113  *
114  * Everything esle is an input file. No arguments or '-' means stdin.
115  *
116  */
117 
118 
119     if ( argc < 1 )
120 	conv();
121     else
122 	while ( argc > 0 ) {
123 	    if ( strcmp(*argv, "-") == 0 )
124 		fp_in = stdin;
125 	    else if ( (fp_in = fopen(*argv, "r")) == NULL )
126 		error(FATAL, "can't open %s", *argv);
127 	    conv();
128 	    if ( fp_in != stdin )
129 		fclose(fp_in);
130 	    argc--;
131 	    argv++;
132 	}   /* End while */
133 
134 }   /* End of arguments */
135 
136 /*****************************************************************************/
137 
conv()138 conv()
139 
140 {
141 
142     int		blocksize;
143     int		blocktype;
144     int		seg;
145     long	ftell();
146 
147 /*
148  *
149  * Font files on the IBM PC are stored in a compressed binary format. Individual
150  * segments in the file are preceeded by a header that looks like,
151  *
152  *		Byte 1:		128
153  *		Byte 2:		segment type (1=ASCII, 2=TOHEX, or 3=EOF)
154  *		Bytes 3-6:	length of the segment
155  *		Bytes 7 ...	data
156  *
157  */
158 
159     while ( 1 ) {
160 	seg = ftell(fp_in);
161 	if ( getc(fp_in) != 128 )
162 	    error(FATAL, "bad file format");
163 	blocktype = getc(fp_in);
164 	blocksize = getint(fp_in);
165 	if ( debug == ON ) {
166 	    fprintf(stderr, "blocktype = %d, blocksize = %d\n", blocktype, blocksize);
167 	    fprintf(stderr, "start=0%o, end=0%o\n", seg, seg+blocksize+6);
168 	    fprintf(stderr, "start=%d, end=%d\n", seg, seg+blocksize+6);
169 	}   /* End if */
170 	switch ( blocktype ) {
171 	    case 1:
172 		asciitext(blocksize);
173 		break;
174 
175 	    case 2:
176 		hexdata(blocksize);
177 		break;
178 
179 	    case 3:
180 		return;
181 
182 	    default:
183 		error(FATAL, "unknown resource type %d", blocktype);
184 	}   /* End switch */
185     }	/* End while */
186 
187 }   /* End of conv */
188 
189 /*****************************************************************************/
190 
asciitext(count)191 asciitext(count)
192 
193     int		count;			/* bytes left in the block */
194 
195 {
196 
197     int		ch;
198     int		i = 0;
199 
200 /*
201  *
202  * Handles type 1 (ie. ASCII text) blocks. Changing carriage returns to newlines
203  * is all I've done.
204  *
205  */
206 
207     for ( i = 0; i < count; i++ ) {
208 	if ( (ch = getc(fp_in)) == '\r' )
209 	    ch = '\n';
210 	putc(ch, fp_out);
211     }	/* End for */
212 
213 }   /* End of asciitext */
214 
215 /*****************************************************************************/
216 
hexdata(count)217 hexdata(count)
218 
219     int		count;			/* bytes left in the block */
220 
221 {
222 
223     int		i;
224     int		n;
225 
226 /*
227  *
228  * Reads the next count bytes and converts each byte to hex. Also starts a new
229  * line every 80 hex characters.
230  *
231  */
232 
233     for ( i = 0, n = 0; i < count; i++ ) {
234 	fprintf(fp_out, "%.2X", getc(fp_in));
235 	if ( (++n % 40) == 0 )
236 	    putc('\n', fp_out);
237     }	/* End for */
238 
239 }   /* End of hexdata */
240 
241 /*****************************************************************************/
242 
getint()243 getint()
244 
245 {
246 
247     int		val;
248 
249 /*
250  *
251  * Reads the next four bytes into an integer and returns the value to the caller.
252  * First two bytes are probably always 0.
253  *
254  */
255 
256     val = getc(fp_in);
257     val |= (getc(fp_in) << 8);
258     val |= (getc(fp_in) << 16);
259     val |= (getc(fp_in) << 24);
260 
261     return(val);
262 
263 }   /* End of getint */
264 
265 /*****************************************************************************/
266 
error(kind,mesg,a1,a2,a3)267 error(kind, mesg, a1, a2, a3)
268 
269     int		kind;
270     char	*mesg;
271     unsigned	a1, a2, a3;
272 
273 {
274 
275 /*
276  *
277  * Print mesg and quit if kind is FATAL.
278  *
279  */
280 
281     if ( mesg != NULL && *mesg != '\0' ) {
282 	fprintf(stderr, "%s: ", prog_name);
283 	fprintf(stderr, mesg, a1, a2, a3);
284 	putc('\n', stderr);
285     }	/* End if */
286 
287     if ( kind == FATAL && ignore == OFF )
288 	exit(x_stat | 01);
289 
290 }   /* End of error */
291 
292 /*****************************************************************************/
293 
294