xref: /plan9/sys/src/cmd/postscript/misc/macfont.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 /*
2  *
3  * Program that converts Macintosh font files to a format that works on Unix
4  * systems. Essentially all the information needed came from the Adobe paper
5  * "Supporting Downloadable PostScript Fonts". To use the program type,
6  *
7  *	macfont font.mac >font.unix
8  *
9  * where font.mac is the font file, exactly as it came over from a Macintosh,
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  * Macintosh 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  *
115  * Everything else is an input file. No arguments or '-' means stdin.
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 
145 /*
146  *
147  * The first four bytes (in a block) are the block size, the fifth is the block
148  * type, and the sixth always appears to be NULL. Type 0 blocks are comments and
149  * are always skipped. Type 1 blocks are ASCII text, type 2 is binary data that
150  * should be converted to hex, while type 5 blocks represent the end of the font
151  * file. Commment block lengths appear to be from the first byte, while other
152  * lengths seem to be measured from block type byte (ie. the fifth byte). Type
153  * four blocks aren't used, while type 3 blocks mean an end of file indication
154  * should be sent to the printer. Haven't done anything with type 3 blocks.
155  *
156  */
157 
158     while ( 1 ) {
159 	blocksize = getint(fp_in);
160 	blocktype = getc(fp_in);
161 	getc(fp_in);
162 	if ( debug == ON )
163 	    fprintf(stderr, "blocktype = %d, blocksize = %d\n", blocktype, blocksize);
164 	switch ( blocktype ) {
165 	    case 0:			/* comment - skip blockcount bytes */
166 		fseek(fp_in, (long) blocksize - 6, 1);
167 		break;
168 
169 	    case 1:
170 		asciitext(blocksize - 2);
171 		break;
172 
173 	    case 2:
174 		hexdata(blocksize - 2);
175 		break;
176 
177 	    case 3:
178 	    case 4:
179 		error(FATAL, "resource type %d not implemented", blocktype);
180 		break;
181 
182 	    case 5:
183 		return;
184 
185 	    default:
186 		error(FATAL, "unknown resource type %d", blocktype);
187 	}   /* End switch */
188     }	/* End while */
189 
190 }   /* End of conv */
191 
192 /*****************************************************************************/
193 
asciitext(count)194 asciitext(count)
195 
196     int		count;			/* bytes left in the block */
197 
198 {
199 
200     int		ch;
201     int		i = 0;
202 
203 /*
204  *
205  * Handles type 1 (ie. ASCII text) blocks. Changing carriage returns to newlines
206  * is all I've done.
207  *
208  */
209 
210     for ( i = 0; i < count; i++ ) {
211 	if ( (ch = getc(fp_in)) == '\r' )
212 	    ch = '\n';
213 	putc(ch, fp_out);
214     }	/* End for */
215 
216 }   /* End of asciitext */
217 
218 /*****************************************************************************/
219 
hexdata(count)220 hexdata(count)
221 
222     int		count;			/* bytes left in the block */
223 
224 {
225 
226     int		i;
227     int		n;
228 
229 /*
230  *
231  * Reads the next count bytes and converts each byte to hex. Also starts a new
232  * line every 80 hex characters.
233  *
234  */
235 
236     for ( i = 0, n = 0; i < count; i++ ) {
237 	fprintf(fp_out, "%.2X", getc(fp_in));
238 	if ( (++n % 40) == 0 )
239 	    putc('\n', fp_out);
240     }	/* End for */
241 
242 }   /* End of hexdata */
243 
244 /*****************************************************************************/
245 
getint()246 getint()
247 
248 {
249 
250     int		val;
251     int		i;
252 
253 /*
254  *
255  * Reads the next four bytes into an integer and returns the value to the caller.
256  * First two bytes are probably always 0.
257  *
258  */
259 
260     for ( i = 0, val = (getc(fp_in) & 0377); i < 3; i++ )
261 	val = (val << 8) | (getc(fp_in) & 0377);
262 
263     return(val);
264 
265 }   /* End of getint */
266 
267 /*****************************************************************************/
268 
error(kind,mesg,a1,a2,a3)269 error(kind, mesg, a1, a2, a3)
270 
271 
272     int		kind;
273     char	*mesg;
274     unsigned	a1, a2, a3;
275 
276 {
277 
278 /*
279  *
280  * Print *mesg then quit if kind is FATAL.
281  *
282  */
283 
284     if ( mesg != NULL && *mesg != '\0' ) {
285 	fprintf(stderr, "%s: ", prog_name);
286 	fprintf(stderr, mesg, a1, a2, a3);
287 	putc('\n', stderr);
288     }	/* End if */
289 
290     if ( kind == FATAL && ignore == OFF )
291 	exit(x_stat | 01);
292 
293 }   /* End of error */
294 
295 /*****************************************************************************/
296 
297