2 "Copyright (c) 1999, 2000 by Arkkra Enterprises\nAll rights reserved\n\n";
4 /* This program generates a Mup fontfile, that will let you override a
5 * Mup font with one of your own. It is done in C rather than with
6 * a "shell script" to be portable to systems without a Unix-like shell.
7 * See the "usage_message" for how to invoke this program.
8 * It creates a PostScript program to print each character in the font
9 * and print out its width, height, and ascent.
10 * It runs Ghostscript on that program.
25 #include <sys/types.h>
30 #define READ_FLAGS (O_RDONLY | O_BINARY)
31 #define WRITE_FLAGS (O_WRONLY | O_BINARY | O_CREAT | O_TRUNC)
33 #define READ_FLAGS (O_RDONLY)
34 #define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)
37 /* temp file used for PostScript program */
38 char *PS_script_file
= "mkmupfnt.ps";
40 char *GS_output
= "mkmupfnt.tmp";
43 char Version
[] = "5.3";
45 void usage(char *program_name
);
46 void verify_valid_Mup_name(char *Mup_name
);
47 int name_matches(char *namelist
[], char *name
, int namelength
);
48 void run_Ghostscript(char *PostScript_name
, char *Mup_name
);
49 char * make_string(char *first_part
, char *second_part
);
50 void generate_PostScript_program(char *PS_file
);
51 void cleanup(int exitcode
);
54 main(int argc
, char **argv
)
56 char *PostScript_name
;
60 fprintf(stderr
, "%s Version %s\n%s", argv
[0], Version
, Copyright
);
62 if (argc
< 4 || argc
> 5) {
66 PostScript_name
= argv
[1];
70 verify_valid_Mup_name(Mup_name
);
72 if ((freopen(outfile
, "w", stdout
)) == (FILE *) 0) {
73 fprintf(stderr
, "Can't open '%s'\n", outfile
);
77 /* Generate a PostScript program to run, and redirect that program
78 * into Ghostscript. */
79 generate_PostScript_program(argc
== 5 ? argv
[4] : (char *) 0);
80 if ((freopen(PS_script_file
, "r", stdin
)) == (FILE *) 0) {
81 fprintf(stderr
, "Can't open '%s'\n", PS_script_file
);
84 run_Ghostscript(PostScript_name
, Mup_name
);
86 /* If there is a PostScript file to add to the output, copy that */
92 if ((file
= open(argv
[4], READ_FLAGS
)) < 0) {
93 fprintf(stderr
, "Can't open '%s'\n", argv
[4]);
96 while ((n
= read(file
, buff
, BUFSIZ
)) > 0) {
103 /* This line is not reached, since cleanup() exits,
104 * but some compilers complain if function doesn't have a
105 * return or exit, so the return is here to appease them. */
110 char *usage_message
=
111 "PostScript_font_name Mup_font_name outfile [file]\n\n"
112 " Generates a fontfile for Mup to use, to override a Mup font.\n"
113 " Arguments are:\n\n"
114 " PostScript_font_name the name of the font you want to add to Mup,\n"
115 " like 'Helvetica-Narrow'\n\n"
116 " Mup_font_name the name of the Mup font you want to replace,\n"
117 " like 'HR' or 'helvetica rom'\n\n"
118 " outfile the generated Mup fontfile\n\n"
119 " file can contain PostScript to be added to Mup prolog,\n"
120 " if needed to use the font.\n";
123 usage(char *program_name
)
125 fprintf(stderr
, "usage: %s %s", program_name
, usage_message
);
129 /* verify Mup font name is a valid one, give error and exit if not */
131 char *family_names
[] = {
142 char *font_names
[] = {
151 verify_valid_Mup_name(char *Mup_name
)
155 if (strlen(Mup_name
) == 2 && strchr("ABCHNPT", Mup_name
[0])
156 && strchr("RBIX", Mup_name
[1]) ) {
157 /* name is okay, an abbreviated name */
161 /* check long names */
162 if ((space_loc
= strchr(Mup_name
, ' ')) != 0 &&
163 name_matches(family_names
, Mup_name
, space_loc
- Mup_name
) &&
164 name_matches(font_names
, space_loc
+ 1, strlen(space_loc
+ 1))) {
168 fprintf(stderr
, "'%s' is not a valid Mup font name\n", Mup_name
);
172 /* verify name given matches one on the list of valid names */
175 name_matches(char *namelist
[], char *name
, int namelength
)
179 for (i
= 0; namelist
[i
] != (char *) 0; i
++) {
180 if (strncmp(namelist
[i
], name
, namelength
) == 0 &&
181 namelength
== strlen(namelist
[i
])) {
189 /* Run Ghostscript to write width/ascent/descent information for all
193 run_Ghostscript(char *PostScript_name
, char *Mup_name
)
198 char * output_option
;
203 /* pass the arguments on to Ghostscript */
204 PS_option
= make_string("-sPostScript_name=", PostScript_name
);
205 Mup_option
= make_string("-sMup_name=", Mup_name
);
207 /* use temp file as a /dev/null */
208 output_option
= make_string("-sOutputFile=", GS_output
);
210 if ((ret
= spawnlp(P_WAIT
, "gs386", "gs386", "-sDEVICE=bit",
211 "-dQUIET", output_option
, Mup_option
,
212 PS_option
, "-", (char *) 0)) != 0) {
213 /* try just plain 'gs' */
214 ret
= spawnlp(P_WAIT
, "gs", "gs", "-sDEVICE=bit",
215 "-dQUIET", output_option
, Mup_option
,
216 PS_option
, "-", (char *) 0);
220 fprintf(stderr
, "failed to execute gs\n");
226 execlp("gs", "gs", "-sDEVICE=bit", "-dQUIET",
227 "-sOutputFile=/dev/null", Mup_option
,
228 PS_option
, "-", (char *) 0);
231 fprintf(stderr
, "failed to execute gs\n");
236 fprintf(stderr
, "Ghostscript failed\n");
243 /* given two strings, get enough space to concatenate them,
244 * write them into the malloc-ed string, and return it. */
247 make_string(char *first_part
, char *second_part
)
251 if ((new_string
= (char *) malloc(strlen(first_part
)
252 + strlen(second_part
) + 1)) == 0) {
253 fprintf(stderr
, "malloc failed\n");
256 sprintf(new_string
, "%s%s", first_part
, second_part
);
260 /* This is the PostScript program that actually extracts the
261 * font size information. It is included here and generated as needed,
262 * so that this can be a standalone program, and not have to search
263 * for another file in order to run. In Unix, we could just pipe this
264 * directly into Ghostscript, but on systems that don't have pipes,
265 * a temp file would need to be used, so we do it that way everywhere
269 char *PostScript_program
=
270 "%% This PostScript program generates a fontfile for use by Mup.\n"
271 "% PostScript_name and Mup_name must be defined as strings\n"
272 "% when this is called.\n"
273 "% PostScript_name is the font you want to add to Mup, while\n"
274 "% Mup_name is name of the Mup font you want to replace.\n"
275 "% So, for example, if you want to replace the Mup Helvetica roman\n"
276 "% font with the PostScript Helvetica-Narrow font, these strings would be\n"
277 "% (Helvetica-Narrow) and (helvetica rom).\n"
278 "% These can be passed in using the Ghostscript -s option.\n"
280 "1 setflat % make bounding box very accurate\n"
282 "/buff 50 string def % number to string conversion buffer\n"
283 "/character 1 string def % buffer for a character to get the bbox of\n"
285 "%------------------------------------------------------------------\n"
289 "% given a one-character string in \"character\",\n"
290 "% outputs its width in 1/1000ths of an inch\n"
293 " % get width of character\n"
294 " character stringwidth\n"
296 " % convert x to 1/1000th of an inch\n"
297 " pop 1000 mul 72 div round cvi\n"
300 " buff cvs (\\t) print print\n"
303 "%-----------------------------------\n"
305 "% given a one-character string in \"character\",\n"
306 "% outputs its height in 1/1000ths of an inch\n"
309 " % place character at (100, 100) and get its pathbbox\n"
312 " character true charpath flattenpath pathbbox\n"
314 " % save the top and bottom y coordinates of the bbox\n"
315 " /top exch def pop\n"
316 " /bot exch def pop\n"
318 " % if bot is above the baseline, the height is (top - baseline)\n"
319 " % otherwise it is (top - bot)\n"
320 " bot 100 gt { top 100 sub } { top bot sub } ifelse\n"
322 " % space is special, use 9 points for height\n"
323 " character ( ) eq { 9 add } if\n"
325 " % add 2 point of padding, one for top and one for bottom white space,\n"
326 " % and convert to 1/1000ths of an inch\n"
327 " 2 add 1000 mul 72 div round cvi\n"
329 " % print the results\n"
330 " buff cvs (\\t) print print\n"
333 "%----------------------------------\n"
335 "% given a one-character string in \"character\",\n"
336 "% outputs its ascent in 1/1000ths of an inch\n"
339 " % place character at (100, 100) and get its pathbbox\n"
342 " character true charpath flattenpath pathbbox\n"
344 " % save the top y coordinate of the bbox\n"
345 " /top exch def pop pop pop\n"
347 " % ascent is top minus baseline\n"
350 " % space is special, use 6.8 points for ascent\n"
351 " character ( ) eq { 6.8 add } if\n"
353 " % add 1 point of padding and convert to 1/1000ths of an inch\n"
354 " 1 add 1000 mul 72 div round cvi\n"
357 " buff cvs (\\t) print print\n"
361 "%-----------------------------------\n"
363 "% generate width, height an ascent for a font.\n"
365 "% fname mupfname do_a_font\n"
368 " % save arguments for later use\n"
369 " /mupfname exch def\n"
373 " (# This is a Mup font file\\n) print\n"
374 " (Mup font name: ) print mupfname print (\\n) print\n"
375 " (PostScript font name: ) print fname buff cvs print (\\n) print\n"
376 " (Size data:\\n) print\n"
378 " % Set up to use the desired font\n"
380 " 12 scalefont setfont\n"
382 " % Mup uses ASCII character codes from 32 through 126\n"
384 " dup buff cvs print\n"
385 " /val exch def character 0 val put\n"
389 " (\\t# ') print character print ('\\n) print\n"
392 " (PostScript:\\n) print\n"
395 "%-----------------------------------\n"
397 "% generate the output\n"
398 "PostScript_name cvn Mup_name do_a_font\n"
403 generate_PostScript_program(char *PS_file
)
408 if ((file
= open(PS_script_file
, WRITE_FLAGS
, 0644)) < 0) {
409 fprintf(stderr
, "Can't generate '%s'\n", PS_script_file
);
413 /* If user gave a PostScript file, that probably implements the
414 * font, so include that in the script */
415 if (PS_file
!= (char *) 0) {
417 write(file
, PS_file
, strlen(PS_file
));
418 write(file
, ") run\n", 6);
421 length
= strlen(PostScript_program
);
422 if (write(file
, PostScript_program
, length
) != length
) {
423 fprintf(stderr
, "generation of PostScript program failed\n");
429 /* remove the temp file and exit */
432 cleanup(int exitcode
)
434 unlink(PS_script_file
);