--- /dev/null
+
+/* Copyright (c) 1999, 2000, 2002, 2005 by Arkkra Enterprises */
+/* All rights reserved */
+
+/* This file contains functions related to fonts,
+ * both user defined and native PostScript fonts.
+ */
+
+#include <string.h>
+#include "defines.h"
+#include "structs.h"
+#include "globals.h"
+
+
+/* The font size info is machine generated, so refer to it here. */
+/* This gives the initialization for FONTINFO structs for all fonts. */
+extern struct FONTINFO Fontinfo[MAXFONTS];
+
+/* map font names to numbers. */
+static struct FONTMAP {
+ char *fontname; /* abbreviated (similar to troff-style)
+ * or full font name */
+ char findex; /* font number */
+} Font_table[] = {
+ /*====== this table must be sorted alphabetically to allow
+ *====== binary search!!!!! */
+ { "AB", FONT_AB },
+ { "AI", FONT_AI },
+ { "AR", FONT_AR },
+ { "AX", FONT_AX },
+ { "BB", FONT_BB },
+ { "BI", FONT_BI },
+ { "BR", FONT_BR },
+ { "BX", FONT_BX },
+ { "CB", FONT_CB },
+ { "CI", FONT_CI },
+ { "CR", FONT_CR },
+ { "CX", FONT_CX },
+ { "HB", FONT_HB },
+ { "HI", FONT_HI },
+ { "HR", FONT_HR },
+ { "HX", FONT_HX },
+ { "NB", FONT_NB },
+ { "NI", FONT_NI },
+ { "NR", FONT_NR },
+ { "NX", FONT_NX },
+ { "PB", FONT_PB },
+ { "PI", FONT_PI },
+ { "PR", FONT_PR },
+ { "PX", FONT_PX },
+ { "TB", FONT_TB },
+ { "TI", FONT_TI },
+ { "TR", FONT_TR },
+ { "TX", FONT_TX },
+ { "avantgarde bold", FONT_AB },
+ { "avantgarde boldital", FONT_AX },
+ { "avantgarde ital", FONT_AI },
+ { "avantgarde rom", FONT_AR },
+ { "bookman bold", FONT_BB },
+ { "bookman boldital", FONT_BX },
+ { "bookman ital", FONT_BI },
+ { "bookman rom", FONT_BR },
+ { "courier bold", FONT_CB },
+ { "courier boldital", FONT_CX },
+ { "courier ital", FONT_CI },
+ { "courier rom", FONT_CR },
+ { "helvetica bold", FONT_HB },
+ { "helvetica boldital", FONT_HX },
+ { "helvetica ital", FONT_HI },
+ { "helvetica rom", FONT_HR },
+ { "newcentury bold", FONT_NB },
+ { "newcentury boldital", FONT_NX },
+ { "newcentury ital", FONT_NI },
+ { "newcentury rom", FONT_NR },
+ { "palatino bold", FONT_PB },
+ { "palatino boldital", FONT_PX },
+ { "palatino ital", FONT_PI },
+ { "palatino rom", FONT_PR },
+ { "times bold", FONT_TB },
+ { "times boldital", FONT_TX },
+ { "times ital", FONT_TI },
+ { "times rom", FONT_TR }
+};
+
+/* Strings to look for in a fontfile */
+char *Mup_name = "Mup font name:";
+char *PostScript_name = "PostScript font name:";
+char *PS_definition = "PostScript:";
+char *Size_data = "Size data:";
+
+/* static functions */
+static int fncmp P((const void *fn1, const void * fn2));
+static char *get_expected P((FILE *fontfile_p, char *filename, char *expected,
+ int *lineno_p));
+static char *get_noncomment P((FILE *fontfile_p, int *lineno_p));
+\f
+
+/* given a font number, return its index into Fontinfo table. FONT_TR
+ * is the first entry in the table.
+ * If the font number given is out of range, pfatal.
+ */
+
+int
+font_index(font)
+
+int font; /* which font */
+
+{
+ if ((font < 0) || (font >= MAXFONTS)) {
+ pfatal("font %d out of range", font);
+ }
+ /* offset relative to first valid font */
+ font = font - FONT_TR;
+
+ return(font);
+}
+\f
+
+/* given a fontname, return its number, or FONT_UNKNOWN */
+
+int
+lookup_font(fontname)
+
+char *fontname;
+
+{
+ struct FONTMAP *finfo_p;
+
+
+ if ((finfo_p = (struct FONTMAP *) bsearch(fontname, Font_table,
+ NUMELEM(Font_table), sizeof(struct FONTMAP), fncmp))
+ != (struct FONTMAP *) 0) {
+ return(finfo_p->findex);
+ }
+ else {
+ return(FONT_UNKNOWN);
+ }
+}
+
+
+
+/* font name comparision function for use by bsearch() */
+
+static int
+fncmp(fn1, fn2)
+
+#ifdef __STDC__
+const void *fn1; /* font name to check */
+const void *fn2; /* pointer to FONTMAP to compare with. declare as char *
+ * since that's what bsearch() thinks it gives us,
+ * then we cast appropriately */
+#else
+char *fn1; /* font name to check */
+char *fn2; /* pointer to FONTMAP to compare with. declare as char *
+ * since that's what bsearch() thinks it gives us, then we
+ * cast appropriately */
+#endif
+
+{
+ return(strcmp(fn1, ((struct FONTMAP *) fn2)->fontname));
+}
+\f
+
+/* Given a font number, return its name. We don't have to do this too often,
+ * it's a simple int compare, and we only need to look through
+ * abbreviated names, so just do linear search. */
+
+char *
+fontnum2name(font)
+
+int font;
+
+{
+ int f;
+ int elements;
+
+ /* divide by 2 because only need to check abbreviations */
+ elements = NUMELEM(Font_table) / 2;
+ for (f = 0; f < elements; f++) {
+ if (Font_table[f].findex == font) {
+ return(Font_table[f].fontname);
+ }
+ }
+ return("unknown");
+}
+\f
+
+/* This handles a fontfile, reading it in, validating its contents,
+ * and saving the information in the Fontinfo array.
+ */
+
+void
+parse_font_file(filename)
+
+char *filename;
+
+{
+ FILE *fontfile_p;
+ char *name; /* Mup font name */
+ char *ps_name; /* PostScript font name */
+ int findex; /* which font is being defined */
+ int c; /* character index */
+ int code; /* "ASCII" code value */
+ int width, height, ascent;
+ char *buffer; /* line read from file */
+ int lineno;
+ int max_height, max_ascent;
+
+
+ debug(2, "parse_font_file(%s)", filename);
+
+ if ((fontfile_p = find_file(&filename)) == (FILE *) 0) {
+ l_yyerror(Curr_filename, yylineno, "can't open '%s'", filename);
+ return;
+ }
+
+ /* first line of file is expected to contain the Mup font name */
+ lineno = 0;
+ if ((name = get_expected(fontfile_p, filename, Mup_name, &lineno))
+ != (char *) 0) {
+ if ((findex = lookup_font(name)) == FONT_UNKNOWN) {
+ l_yyerror(filename, lineno,
+ "'%s' is not a valid Mup font name", name);
+ return;
+ }
+ findex = font_index(findex);
+
+ if (Fontinfo[findex].fontfile != (FILE *) 0) {
+ l_yyerror(filename, lineno,
+ "Font '%s' redefined more than once", name);
+ return;
+ }
+ /* Save the file pointer, since we'll need to read the rest of
+ * the file to put into the Mup output */
+ Fontinfo[findex].fontfile = fontfile_p;
+ }
+ else {
+ return;
+ }
+
+ /* Next line of file is expected to contain the PostScript font name */
+ if ((ps_name = get_expected(fontfile_p, filename, PostScript_name, &lineno))
+ != (char *) 0) {
+ if (strlen(ps_name) == 0 ) {
+ l_yyerror(filename, lineno,
+ "No PostScript font name value given");
+ return;
+ }
+ Fontinfo[findex].ps_name = ps_name;
+ }
+ else {
+ return;
+ }
+
+ /* Next line of file is expected to contain the Size data line */
+ if ((ps_name = get_expected(fontfile_p, filename, Size_data, &lineno))
+ == (char *) 0) {
+ return;
+ }
+
+ max_height = max_ascent = 0;
+ for (c = FIRST_CHAR; c < FIRST_CHAR + CHARS_IN_FONT - 1; c++) {
+ buffer = get_noncomment(fontfile_p, &lineno);
+ if ( sscanf(buffer, "%d %d %d %d",
+ &code, &width, &height, &ascent) != 4) {
+ buffer[strlen(buffer) - 1] = '\0';
+ l_yyerror(filename, lineno,
+ "size data line has incorrect format: '%s'",
+ buffer);
+ return;
+ }
+ if (c != code) {
+ l_yyerror(filename, lineno,
+ "expecting size data for character %d, but got %d instead",
+ c, code);
+ return;
+ }
+
+ /* Because of how backspace works (see comment in defines.h)
+ * we need to limit width to 0.5 inch for a DEFAULT_SIZE
+ * character. */
+ if (width > 500) {
+ l_yyerror(filename, lineno, "width must be less than 500");
+ return;
+ }
+
+ /* save size in table */
+ code = CHAR_INDEX(code);
+ Fontinfo[findex].ch_height[code] = height;
+ Fontinfo[findex].ch_width[code] = width;
+ Fontinfo[findex].ch_ascent[code] = ascent;
+
+ if (height > max_height) {
+ max_height = height;
+ }
+ if (ascent > max_ascent) {
+ max_ascent = ascent;
+ }
+ }
+
+ Maxfontheight[findex] = (double) max_height / (double) FONTFACTOR;
+ Maxfontascent[findex] = (double) max_ascent / (double) FONTFACTOR;
+
+ /* Next line of file is expected to contain the PostScript: line */
+ if ((ps_name = get_expected(fontfile_p, filename, PS_definition, &lineno))
+ == (char *) 0) {
+ return;
+ }
+}
+\f
+
+/* Read from given file. If next non-comment line starts as expected,
+ * return a copy of the rest of the line after any white space.
+ * Otherwise print an error and return 0.
+ */
+
+static char *
+get_expected(fontfile_p, filename, expected, lineno_p)
+
+FILE *fontfile_p;
+char *filename;
+char *expected; /* line read is expected to start with this */
+int *lineno_p; /* line number where line was found is returned here */
+
+{
+ char *buffer;
+ char *newstring;
+ char *p;
+
+ buffer = get_noncomment(fontfile_p, lineno_p);
+ if (strncmp(buffer, expected, strlen(expected)) != 0) {
+ l_yyerror(filename, *lineno_p,
+ "Expecting '%s' in font_file '%s'", expected, filename);
+ return((char *) 0);
+ }
+
+ /* skip any leading white space */
+ for (buffer += strlen(expected); isspace(*buffer); buffer++) {
+ ;
+ }
+
+ /* trim any white space from the end of the string */
+ for (p = buffer + strlen(buffer) - 1; p >= buffer; p--) {
+ if (isspace(*p)) {
+ *p = '\0';
+ }
+ else {
+ break;
+ }
+ }
+
+ /* make a copy and return it */
+ MALLOCA(char, newstring, strlen(buffer) + 1);
+ strcpy(newstring, buffer);
+ return(newstring);
+}
+\f
+
+/* Read lines from given file until a non-comment line is found, and
+ * return that line. A comment is a line that has # in its first column.
+ * Returns a null string on end of file. The line returned is in a static
+ * buffer overwritten on each call, so caller must save if they need a copy.
+ */
+
+static char *
+get_noncomment(file, lineno_p)
+
+FILE *file;
+int *lineno_p; /* line number gets sents in and returned here */
+
+{
+ static char buffer[128];
+
+ while (fgets(buffer, sizeof(buffer), file) != (char *) 0) {
+ (*lineno_p)++;
+ if ( *buffer != '#') {
+ /* not a comment, so return it */
+ return(buffer);
+ }
+ }
+ buffer[0] = '\0';
+ return(buffer);
+}
+\f
+
+/* return the height for a font in inches for a given size */
+
+double
+fontheight(font, size)
+
+int font;
+int size;
+
+{
+ return( (double) Maxfontheight[font_index(font)] *
+ ((double) size / (double) DFLT_SIZE) );
+}
+
+
+
+/* return the ascent for a font in inches for a given size */
+
+double
+fontascent(font, size)
+
+int font;
+int size;
+
+{
+ return( (double) Maxfontascent[font_index(font)] *
+ ((double) size / (double) DFLT_SIZE) );
+}
+
+
+
+/* return the descent for a font in inches for a given size */
+
+double
+fontdescent(font, size)
+
+int font;
+int size;
+
+{
+ return( fontheight(font, size) - fontascent (font, size) );
+}