--- /dev/null
+char Copyright[] =
+ "Copyright (c) 1999, 2000 by Arkkra Enterprises\nAll rights reserved\n\n";
+
+/* This program generates a Mup fontfile, that will let you override a
+ * Mup font with one of your own. It is done in C rather than with
+ * a "shell script" to be portable to systems without a Unix-like shell.
+ * See the "usage_message" for how to invoke this program.
+ * It creates a PostScript program to print each character in the font
+ * and print out its width, height, and ascent.
+ * It runs Ghostscript on that program.
+ */
+
+#ifdef __DJGPP__
+#define __DOS__
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#ifdef __DOS__
+#include <process.h>
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif
+
+#ifdef O_BINARY
+#define READ_FLAGS (O_RDONLY | O_BINARY)
+#define WRITE_FLAGS (O_WRONLY | O_BINARY | O_CREAT | O_TRUNC)
+#else
+#define READ_FLAGS (O_RDONLY)
+#define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)
+#endif
+
+/* temp file used for PostScript program */
+char *PS_script_file = "mkmupfnt.ps";
+#ifdef __DOS__
+char *GS_output = "mkmupfnt.tmp";
+#endif
+
+char Version[] = "5.3";
+
+void usage(char *program_name);
+void verify_valid_Mup_name(char *Mup_name);
+int name_matches(char *namelist[], char *name, int namelength);
+void run_Ghostscript(char *PostScript_name, char *Mup_name);
+char * make_string(char *first_part, char *second_part);
+void generate_PostScript_program(char *PS_file);
+void cleanup(int exitcode);
+
+int
+main(int argc, char **argv)
+{
+ char *PostScript_name;
+ char *Mup_name;
+ char *outfile;
+
+ fprintf(stderr, "%s Version %s\n%s", argv[0], Version, Copyright);
+
+ if (argc < 4 || argc > 5) {
+ usage(argv[0]);
+ }
+
+ PostScript_name = argv[1];
+ Mup_name = argv[2];
+ outfile = argv[3];
+
+ verify_valid_Mup_name(Mup_name);
+
+ if ((freopen(outfile, "w", stdout)) == (FILE *) 0) {
+ fprintf(stderr, "Can't open '%s'\n", outfile);
+ exit(1);
+ }
+
+ /* Generate a PostScript program to run, and redirect that program
+ * into Ghostscript. */
+ generate_PostScript_program(argc == 5 ? argv[4] : (char *) 0);
+ if ((freopen(PS_script_file, "r", stdin)) == (FILE *) 0) {
+ fprintf(stderr, "Can't open '%s'\n", PS_script_file);
+ cleanup(1);
+ }
+ run_Ghostscript(PostScript_name, Mup_name);
+
+ /* If there is a PostScript file to add to the output, copy that */
+ if (argc == 5) {
+ int file;
+ int n;
+ char buff[BUFSIZ];
+
+ if ((file = open(argv[4], READ_FLAGS)) < 0) {
+ fprintf(stderr, "Can't open '%s'\n", argv[4]);
+ cleanup(1);
+ }
+ while ((n = read(file, buff, BUFSIZ)) > 0) {
+ write(1, buff, n);
+ }
+ close(file);
+ }
+
+ cleanup(0);
+ /* This line is not reached, since cleanup() exits,
+ * but some compilers complain if function doesn't have a
+ * return or exit, so the return is here to appease them. */
+ return(0);
+}
+
+
+char *usage_message =
+ "PostScript_font_name Mup_font_name outfile [file]\n\n"
+ " Generates a fontfile for Mup to use, to override a Mup font.\n"
+ " Arguments are:\n\n"
+ " PostScript_font_name the name of the font you want to add to Mup,\n"
+ " like 'Helvetica-Narrow'\n\n"
+ " Mup_font_name the name of the Mup font you want to replace,\n"
+ " like 'HR' or 'helvetica rom'\n\n"
+ " outfile the generated Mup fontfile\n\n"
+ " file can contain PostScript to be added to Mup prolog,\n"
+ " if needed to use the font.\n";
+
+void
+usage(char *program_name)
+{
+ fprintf(stderr, "usage: %s %s", program_name, usage_message);
+ exit(1);
+}
+
+/* verify Mup font name is a valid one, give error and exit if not */
+
+char *family_names[] = {
+ "avantegarde",
+ "bookman",
+ "courier",
+ "helvetica",
+ "newcentury",
+ "palatino",
+ "times",
+ (char *) 0
+};
+
+char *font_names[] = {
+ "rom",
+ "bold",
+ "ital",
+ "boldital",
+ (char *) 0
+};
+
+void
+verify_valid_Mup_name(char *Mup_name)
+{
+ char *space_loc;
+
+ if (strlen(Mup_name) == 2 && strchr("ABCHNPT", Mup_name[0])
+ && strchr("RBIX", Mup_name[1]) ) {
+ /* name is okay, an abbreviated name */
+ return;
+ }
+
+ /* check long names */
+ if ((space_loc = strchr(Mup_name, ' ')) != 0 &&
+ name_matches(family_names, Mup_name, space_loc - Mup_name) &&
+ name_matches(font_names, space_loc + 1, strlen(space_loc + 1))) {
+ return;
+ }
+
+ fprintf(stderr, "'%s' is not a valid Mup font name\n", Mup_name);
+ exit(1);
+}
+
+/* verify name given matches one on the list of valid names */
+
+int
+name_matches(char *namelist[], char *name, int namelength)
+{
+ int i;
+
+ for (i = 0; namelist[i] != (char *) 0; i++) {
+ if (strncmp(namelist[i], name, namelength) == 0 &&
+ namelength == strlen(namelist[i])) {
+ /* matches */
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/* Run Ghostscript to write width/ascent/descent information for all
+ * characters. */
+
+void
+run_Ghostscript(char *PostScript_name, char *Mup_name)
+{
+ char * PS_option;
+ char * Mup_option;
+#ifdef __DOS__
+ char * output_option;
+ int ret;
+#endif
+ int status;
+
+ /* pass the arguments on to Ghostscript */
+ PS_option = make_string("-sPostScript_name=", PostScript_name);
+ Mup_option = make_string("-sMup_name=", Mup_name);
+#ifdef __DOS__
+ /* use temp file as a /dev/null */
+ output_option = make_string("-sOutputFile=", GS_output);
+
+ if ((ret = spawnlp(P_WAIT, "gs386", "gs386", "-sDEVICE=bit",
+ "-dQUIET", output_option, Mup_option,
+ PS_option, "-", (char *) 0)) != 0) {
+ /* try just plain 'gs' */
+ ret = spawnlp(P_WAIT, "gs", "gs", "-sDEVICE=bit",
+ "-dQUIET", output_option, Mup_option,
+ PS_option, "-", (char *) 0);
+ }
+ unlink(GS_output);
+ if (ret != 0) {
+ fprintf(stderr, "failed to execute gs\n");
+ cleanup(1);
+ }
+#else
+ switch (fork()) {
+ case 0:
+ execlp("gs", "gs", "-sDEVICE=bit", "-dQUIET",
+ "-sOutputFile=/dev/null", Mup_option,
+ PS_option, "-", (char *) 0);
+ /* FALL THROUGH */
+ case -1:
+ fprintf(stderr, "failed to execute gs\n");
+ cleanup(1);
+ default:
+ wait( &status);
+ if (status != 0) {
+ fprintf(stderr, "Ghostscript failed\n");
+ cleanup(1);
+ }
+ }
+#endif
+}
+
+/* given two strings, get enough space to concatenate them,
+ * write them into the malloc-ed string, and return it. */
+
+char *
+make_string(char *first_part, char *second_part)
+{
+ char *new_string;
+
+ if ((new_string = (char *) malloc(strlen(first_part)
+ + strlen(second_part) + 1)) == 0) {
+ fprintf(stderr, "malloc failed\n");
+ cleanup(1);
+ }
+ sprintf(new_string, "%s%s", first_part, second_part);
+ return(new_string);
+}
+
+/* This is the PostScript program that actually extracts the
+ * font size information. It is included here and generated as needed,
+ * so that this can be a standalone program, and not have to search
+ * for another file in order to run. In Unix, we could just pipe this
+ * directly into Ghostscript, but on systems that don't have pipes,
+ * a temp file would need to be used, so we do it that way everywhere
+ * for consistency.
+ */
+
+char *PostScript_program =
+"%% This PostScript program generates a fontfile for use by Mup.\n"
+"% PostScript_name and Mup_name must be defined as strings\n"
+"% when this is called.\n"
+"% PostScript_name is the font you want to add to Mup, while\n"
+"% Mup_name is name of the Mup font you want to replace.\n"
+"% So, for example, if you want to replace the Mup Helvetica roman\n"
+"% font with the PostScript Helvetica-Narrow font, these strings would be\n"
+"% (Helvetica-Narrow) and (helvetica rom).\n"
+"% These can be passed in using the Ghostscript -s option.\n"
+"\n"
+"1 setflat % make bounding box very accurate\n"
+"\n"
+"/buff 50 string def % number to string conversion buffer\n"
+"/character 1 string def % buffer for a character to get the bbox of\n"
+"\n"
+"%------------------------------------------------------------------\n"
+"\n"
+"\n"
+"% Usage\n"
+"% given a one-character string in \"character\",\n"
+"% outputs its width in 1/1000ths of an inch\n"
+"\n"
+"/getwidth {\n"
+" % get width of character\n"
+" character stringwidth\n"
+"\n"
+" % convert x to 1/1000th of an inch\n"
+" pop 1000 mul 72 div round cvi\n"
+"\n"
+" % print results\n"
+" buff cvs (\\t) print print\n"
+"} def\n"
+"\n"
+"%-----------------------------------\n"
+"% Usage\n"
+"% given a one-character string in \"character\",\n"
+"% outputs its height in 1/1000ths of an inch\n"
+"\n"
+"/getheight {\n"
+" % place character at (100, 100) and get its pathbbox\n"
+" newpath\n"
+" 100 100 moveto\n"
+" character true charpath flattenpath pathbbox\n"
+"\n"
+" % save the top and bottom y coordinates of the bbox\n"
+" /top exch def pop\n"
+" /bot exch def pop\n"
+"\n"
+" % if bot is above the baseline, the height is (top - baseline)\n"
+" % otherwise it is (top - bot)\n"
+" bot 100 gt { top 100 sub } { top bot sub } ifelse\n"
+"\n"
+" % space is special, use 9 points for height\n"
+" character ( ) eq { 9 add } if\n"
+"\n"
+" % add 2 point of padding, one for top and one for bottom white space,\n"
+" % and convert to 1/1000ths of an inch\n"
+" 2 add 1000 mul 72 div round cvi\n"
+"\n"
+" % print the results\n"
+" buff cvs (\\t) print print\n"
+"} def\n"
+"\n"
+"%----------------------------------\n"
+"% Usage\n"
+"% given a one-character string in \"character\",\n"
+"% outputs its ascent in 1/1000ths of an inch\n"
+"\n"
+"/getascent {\n"
+" % place character at (100, 100) and get its pathbbox\n"
+" newpath\n"
+" 100 100 moveto\n"
+" character true charpath flattenpath pathbbox\n"
+"\n"
+" % save the top y coordinate of the bbox\n"
+" /top exch def pop pop pop\n"
+"\n"
+" % ascent is top minus baseline\n"
+" top 100 sub\n"
+"\n"
+" % space is special, use 6.8 points for ascent\n"
+" character ( ) eq { 6.8 add } if\n"
+"\n"
+" % add 1 point of padding and convert to 1/1000ths of an inch\n"
+" 1 add 1000 mul 72 div round cvi\n"
+"\n"
+" % print results\n"
+" buff cvs (\\t) print print\n"
+"} def\n"
+"\n"
+"\n"
+"%-----------------------------------\n"
+"\n"
+"% generate width, height an ascent for a font.\n"
+"% Usage:\n"
+"% fname mupfname do_a_font\n"
+"\n"
+"/do_a_font {\n"
+" % save arguments for later use\n"
+" /mupfname exch def\n"
+" /fname exch def\n"
+"\n"
+" % Outut heading\n"
+" (# This is a Mup font file\\n) print\n"
+" (Mup font name: ) print mupfname print (\\n) print\n"
+" (PostScript font name: ) print fname buff cvs print (\\n) print\n"
+" (Size data:\\n) print\n"
+"\n"
+" % Set up to use the desired font\n"
+" fname findfont\n"
+" 12 scalefont setfont\n"
+"\n"
+" % Mup uses ASCII character codes from 32 through 126\n"
+" 32 1 126 {\n"
+" dup buff cvs print\n"
+" /val exch def character 0 val put\n"
+" getwidth\n"
+" getheight\n"
+" getascent\n"
+" (\\t# ') print character print ('\\n) print\n"
+" } for\n"
+"\n"
+" (PostScript:\\n) print\n"
+"} def\n"
+"\n"
+"%-----------------------------------\n"
+"\n"
+"% generate the output\n"
+"PostScript_name cvn Mup_name do_a_font\n"
+"\n"
+"quit\n";
+
+void
+generate_PostScript_program(char *PS_file)
+{
+ int file;
+ int length;
+
+ if ((file = open(PS_script_file, WRITE_FLAGS, 0644)) < 0) {
+ fprintf(stderr, "Can't generate '%s'\n", PS_script_file);
+ exit(1);
+ }
+
+ /* If user gave a PostScript file, that probably implements the
+ * font, so include that in the script */
+ if (PS_file != (char *) 0) {
+ write(file, "(", 1);
+ write(file, PS_file, strlen(PS_file));
+ write(file, ") run\n", 6);
+ }
+
+ length = strlen(PostScript_program);
+ if (write(file, PostScript_program, length) != length) {
+ fprintf(stderr, "generation of PostScript program failed\n");
+ cleanup(1);
+ }
+ close(file);
+}
+
+/* remove the temp file and exit */
+
+void
+cleanup(int exitcode)
+{
+ unlink(PS_script_file);
+ exit(exitcode);
+}