/************************************************************************/ /************************************************************************/ /* */ /* i f t e x p l g e n . c */ /* */ /* Program to generate TeX PL files. Options are: */ /* */ /* -D directory output directory */ /* -F file name of Font Information File */ /* -d debug */ /* -r resident map directory */ /* */ /************************************************************************/ /************************************************************************/ /* */ /* Copyright 1985 IMAGEN Corporation */ /* 2650 San Tomas Expressway */ /* P.O. Box 58101 */ /* Santa Clara, CA 95052-8101 */ /* (408) 986-9400 */ /* */ /************************************************************************/ /************************************************************************/ #include #include #ifdef SYSV #define sys5 #else #ifdef SYSIII #define sys5 #endif #endif #ifdef sys5 # include # define index(s,c) strchr(s,c) # define rindex(s,c) strrchr(s,c) # define bcopy(a,b,c) memcpy(b,a,c) # define bzero(a,b) memset(a,0,b) #else # include #endif #ifndef RESDirectory # define RESDirectory "/usr/lib/tex/fonts/resident" #endif RESDirectory # define RES_FILE "resident" /************************************************************************/ /* */ /* GLOBAL DEFINES */ /* */ /************************************************************************/ # define TRUE 1 # define FALSE 0 # define G(A,B) ((A)*256+(B)) /* Gascii number */ # define FIX_2_POINTS(X) ( (X) >> 20 ) /* Fixes to points */ # define POINTS_2_FIX(X) ( (X) << 20 ) /* Points to fixes */ /************************************************************************/ /* */ /* To Convert Pixels Per Inch into Points, the following values */ /* are used: */ /* */ /* Pixels/(resolution) = inches */ /* Points/(72.27) = inches */ /* */ /************************************************************************/ # define PIX_2_POINTS(X) (((long)(X) * 7227L)/(resolution*100L)) /* Pixels to points */ # define PIX_2_FIX(X) ( POINTS_2_FIX(PIX_2_POINTS(X)) ) /* THIS NEEDS TO BE CHANGED!! */ # define MAX_FONTS 128 /* Never more fonts than this */ # define MAX_CHARS 256 /* Never more chars than this */ # define MAX_SIZES 32 /* Never more sizes in a font */ # define MAX_FILENAME 64 # define MAX_STRING 256 /* strings are shorter than this*/ # define MAX_ORDERS 20 /* Maximum # char order files */ # define MAX_GASCII 65535 /* Max gascii # */ /************************************************************************/ /* */ /* LIGATURE TABLES */ /* */ /************************************************************************/ typedef struct { unsigned short lig_first; /* First character of ligature */ unsigned short lig_second; /* Second character of ligature */ unsigned short lig_replace; /* Replacement character */ } LIGTABLE; LIGTABLE ligatures[] = { G(0,102), G(0,102), G(240,33), /* ff */ G(240,33), G(0,105), G(240,34), /* ffi */ G(240,33), G(0,108), G(240,35), /* ffl */ G(0,102), G(0,105), G(240,36), /* fi */ G(0,102), G(0,108), G(240,37), /* fl */ 0, 0, 0 }; /************************************************************************/ /* */ /* CHARACTER ORDERING */ /* */ /************************************************************************/ typedef struct { /* Struct for giving character order */ /* of a particular type of font */ unsigned short co_gascii[MAX_CHARS]; /* character ordering */ char co_file[MAX_FILENAME]; /* file containing map */ char co_id[MAX_STRING]; /* identification string */ } CHARORDER; typedef struct { char m_name[MAX_FILENAME]; /* font name */ int m_number; /* character order index */ } MAP_INDEX; /************************************************/ /* */ /* Hard coded font parameters */ /* */ /************************************************/ # define SPACE_DIV ( 3 ) /* Divide point size by this to */ /* get size of a space */ # define STRETCH_DIV ( 6 ) /* Divide point size by this to */ /* get stretch value */ # define SHRINK_DIV ( 12 ) /* Divide point size by this to */ /* get shrink value */ # define LC_X ( (unsigned short) G(0,120) ) /* Gascii number for lc x */ # define EXTRA_DIV ( 75 ) /* Divide point size by this to */ /* get EXTRASPACE value ( * 10) */ # define PL_SUFFIX ".pl" int debug = FALSE; /* TRUE if output debug code */ char *pgm_name; /* Name of this program */ int num_fonts; /* No. fonts in FIF */ ifchrinf chrinf[MAX_CHARS]; /* current character info used */ iffntidx base_fntidx[MAX_FONTS]; /* The entire font index */ iffsmapb base_fsmapb[MAX_SIZES]; /* The entire font size map */ long point_size; /* Cur. point size in fixes */ long resolution; /* Resolution of the font */ extern char *ifinfile; /* Font Info File name */ char *out_dir = "."; /* Output directory */ char *res_dir = RESDirectory;/* resident font directory */ char res_file[MAX_FILENAME]; /* resident font file name */ MAP_INDEX map_base[MAX_FONTS]; int max_map = 0; /* number of maps */ CHARORDER order_map[MAX_ORDERS]; /* character orderings */ int max_order = 0; /* number of orders */ /************************************************************************/ /* */ /* int igetopt ( argc, argv, optstring) */ /* int argc; */ /* char **argv, *opstring; */ /* */ /************************************************************************/ int optind = 1; /* next argv to process */ int opterr = 0; /* Non-zero disables errors msgs*/ char *optarg = NULL; /* Pointer to option argument */ static char *next_opt = NULL; /* Pointer to next option */ /* If NULL, grab next argv */ int igetopt(argc, argv, optstring) int argc; /* number or arguments */ char **argv; /* array or arguments */ char *optstring; /* option string */ { char *option; /* current option found */ char *match; /* matched option in optstring */ int return_code; /* Value to be returned */ /* */ /* Get the next option */ /* */ if ( next_opt == NULL ) { /* */ /* No more arguments */ /* */ if ( optind >= argc ) return( EOF ); next_opt = argv[optind]; /* */ /* End of options */ /* */ if ( *next_opt != '-' ) return( EOF ); /* */ /* Single '-', end of opts */ /* */ if ( *(++next_opt) == '\0' ) return( EOF ); optind++; } option = next_opt; /* */ /* Case of '--' */ /* Force end of options */ /* */ if ( *option == '-' ) return( EOF ); /* */ /* See if option is in optstring */ /* */ if ( (match=index(optstring, *option)) == NULL ) { if ( opterr == 0 ) fprintf(stderr, "Illegal option '%c'\n", *option); next_opt = option + 1; if ( *next_opt == '\0' ) next_opt = NULL; return( (int) '?' ); } return_code = (int) ( *option++ ); /* */ /* Argument follows this option */ /* */ if ( *(++match) == ':' ) { /* */ /* Set optarg to proper value */ /* */ if ( *option != '\0' ) optarg = option; else if ( optind < argc ) optarg = argv[optind++]; else { if ( opterr == 0 ) fprintf(stderr, "Option error: missing argument for '%c'\n", return_code); optarg = ""; } /* */ /* Locate the next option */ /* */ next_opt = NULL; } else { next_opt = option; if ( *next_opt == '\0' ) next_opt = NULL; } return( return_code ); } /************************************************************************/ /* */ /* MAIN ROUTINE */ /* */ /* initialize, parse options */ /* */ /************************************************************************/ # define OPTIONS "dD:F:r:" main(argc, argv) int argc; char **argv; { int option; /* Current option */ int i; /* Incrementor */ FILE *res_fp; /* File pointer, resident map */ pgm_name = argv[0]; while ( (option = igetopt(argc, argv, OPTIONS) ) != EOF ) { switch( (char) option ) { case 'd': debug = TRUE; break; case 'D': out_dir = optarg; break; case 'F': ifinfile = optarg; break; case 'r': res_dir = optarg; break; case '?': fprintf(stderr, "Usage: %s [%s]\n", pgm_name, OPTIONS); exit(1); } } sprintf(res_file, "%s/%s", res_dir, RES_FILE); if ( debug ) { fprintf(stderr, "Resident map is %s\n", res_file); fprintf(stderr, "Output directory is %s\n", out_dir); } /* */ /* Get Font Indices */ /* */ ifgetfd(); num_fonts = ifgettoc( (short) MAX_FONTS, base_fntidx ); switch( (char) num_fonts ) { case (char) -1: fputs(pgm_name, stderr); perror("Font Information File"); exit(1); case (char) -2: fputs(pgm_name, stderr); fprintf(stderr, "Font Info file has more than %d fonts\n", MAX_FONTS ); exit(1); case (char) -3: fputs(pgm_name, stderr); fputs("Bad Font info file\n", stderr); exit(1); } if ( (res_fp=fopen(res_file, "r")) == NULL ) { perror(res_file); exit(1); } read_res(res_fp); fclose(res_fp); /* */ /* If no arguments follow the options, then*/ /* generate PL files for each font. Else, */ /* only do PL files for fonts indicated */ /* */ if ( optind == argc ) { for ( i=0 ; ifx_iprfx; while ( *c != ' ' ) c++; length = c - font_index->fx_iprfx; if ( strncmp(name, font_index->fx_iprfx, length ) == 0 ) { if ( length == strlen(name) ) return(0); if ( strncmp(&(name[length]), font_index->fx_style, strlen(&(name[length])) ) == 0 ) return(0); } return(1); } /************************************************************************/ /* */ /* pl_gen( iffntidx * ) */ /* */ /* Generate a set of PL files for the given font */ /* */ /************************************************************************/ pl_gen(fntidx) iffntidx *fntidx; { int num_sizes; int i, j; MAP_INDEX *map_ptr; num_sizes = ifgetsizes(fntidx->fx_iprfx, fntidx->fx_style, (iffntinf *) 0, (short) MAX_SIZES, base_fsmapb); switch( (char) num_sizes ) { case (char) -1: perror(pgm_name); exit(1); case (char) -2: fprintf(stderr, "%s: Font/style not found!!\n", pgm_name); exit(1); case (char) -3: fprintf(stderr, "%s: Font has more than %d sizes\n", pgm_name, MAX_SIZES); exit(1); case (char) -4: fprintf(stderr, "%s: Bad Font Info File\n", pgm_name); exit(1); } /* */ /* Foreach point size of this font, */ /* create the PL file */ /* */ for ( i=0 ; im_name) == (index(fntidx->fx_iprfx,' ')-fntidx->fx_iprfx) && strncmp(map_ptr->m_name, fntidx->fx_iprfx, strlen(map_ptr->m_name) ) == 0 ) { point_size = base_fsmapb[i].mb_start.sz_fixes; create_pl( map_ptr->m_number, fntidx); break; } } if ( j==max_map ) { fprintf(stderr, "%s : Cannot find a match for a font\n", pgm_name); exit(1); } } } /************************************************************************/ /* */ /* create_pl( int, iffntidx *, long) */ /* */ /* For the given font/style/size, generate a PL file */ /* */ /************************************************************************/ create_pl(order_number, fntidx) int order_number; /* Type of map to use */ iffntidx *fntidx; /* Current Font Index Entry */ { int fif_rc; /* Returncode from FIF access */ char temp[MAX_FILENAME]; /* Used to build PL filename */ FILE *pl_fp; /* File pointer for PL file */ int i; /* incrementor */ iffsinfb fsinfb; /* Font Size Info */ iffntinf fntinf; /* Font Information */ char outname[MAX_FILENAME]; /* filename of output file */ unsigned short *g_ptr; /* gascii array pointer */ CHARORDER *cur_order; /* Current order pointer */ ifchrinf *ch_ptr; /* pointer for char info */ temp[0] = '\0'; strncat(temp, fntidx->fx_iprfx, (index(fntidx->fx_iprfx, ' ') - fntidx->fx_iprfx) ); strncat(temp, fntidx->fx_style, (index(fntidx->fx_style, ' ') - fntidx->fx_style) ); sprintf(outname, "%s/%s%d%s", out_dir, temp, FIX_2_POINTS(point_size), PL_SUFFIX); fprintf(stderr, "Producing %s\n", outname); if ( (pl_fp=fopen(outname, "w")) == NULL ) { fprintf(stderr, "%s : ", pgm_name); perror(outname); exit(1); } cur_order = &(order_map[order_number]); bzero( (char *) chrinf, MAX_CHARS * sizeof(ifchrinf) ); fif_rc = ifgetinfo( fntidx->fx_iprfx, fntidx->fx_style, point_size, (long) 0, /* Not isomorphic */ &fntinf, &fsinfb, (short) MAX_CHARS, cur_order->co_gascii, (ifgcmapb *) 0, chrinf, (short *) 0 ); switch( (char) fif_rc ) { case (char) -1: fprintf(stderr, "%s: ", pgm_name); perror("Font Info File"); exit(1); case (char) -2: fprintf(stderr, "%s: Font/style not found\n", pgm_name); exit(1); case (char) -3: fprintf(stderr, "%s: Font size not found\n", pgm_name); exit(1); case (char) -4: fprintf(stderr, "%s: Font Info File corrupted\n", pgm_name); exit(1); case (char) -5: fprintf(stderr, "%s: INTERNAL ERROR\n", pgm_name); exit(1); } resolution = fntinf.fi_hnres; fprintf(pl_fp, "(CHECKSUM O 0)\n"); fprintf(pl_fp, "(DESIGNSIZE R %d.0)\n", FIX_2_POINTS(point_size) ); fprintf(pl_fp, "(CODINGSCHEME %s)\n", cur_order->co_id); fprintf(pl_fp, "(FAMILY %s%d)\n", temp, FIX_2_POINTS(point_size) ); fputs("(FONTDIMEN\n", pl_fp); /* CHECK FOR ITALICS */ if ( strncmp(fntidx->fx_style, "i", strlen("i")) == 0 ) { fputs(" (SLANT R 0.25)\n", pl_fp); } else { fputs(" (SLANT R 0.0)\n", pl_fp); } fputs(" (QUAD R 1.0)\n", pl_fp); if ( fsinfb.ib_msadw.sz_pxels == 0 ) { out_2_7("SPACE", point_size/SPACE_DIV, pl_fp); out_2_7("EXTRASPACE", (point_size*10)/EXTRA_DIV, pl_fp); } else { out_2_7("SPACE", fsinfb.ib_msadw.sz_fixes, pl_fp); out_2_7("EXTRASPACE", fsinfb.ib_msadw.sz_fixes, pl_fp); } out_2_7("STRETCH", point_size/STRETCH_DIV, pl_fp); out_2_7("SHRINK", point_size/SHRINK_DIV, pl_fp); for ( g_ptr=cur_order->co_gascii,i=0 ; ico_gascii,ch_ptr=chrinf,i=0 ; ich_hght == 0 || ch_ptr->ch_width == 0 ) continue; fprintf(pl_fp, "(CHARACTER O %o\n", i); out_2_7("CHARWD", ch_ptr->ch_advwt.sz_fixes, pl_fp ); out_2_7("CHARHT", PIX_2_FIX(ch_ptr->ch_topof), pl_fp ); fprintf(pl_fp, " (COMMENT GASCII %d.%d)\n", (*g_ptr >> 8) & 0xff, *g_ptr & 0xff); if ( (ch_ptr->ch_hght - ch_ptr->ch_topof) != 0 ) out_2_7("CHARDP", PIX_2_FIX( ch_ptr->ch_hght - ch_ptr->ch_topof), pl_fp ); fputs(" )\n", pl_fp); } fclose(pl_fp); } /************************************************************************/ /* */ /* out_2_7( char *, long, FILE *) */ /* */ /* Routine to output a fix_word in %2.7f format. */ /* Lower 20 bits form the fraction. Upper 10 are the integer. */ /* */ /* This code literally translated from the TFtoPL program */ /* */ /************************************************************************/ out_2_7(name, fix_word, fp) char *name; FILE *fp; long fix_word; { int i = 7; fix_word = fix_word / FIX_2_POINTS(point_size); fprintf(fp, " (%s R %2d.", name, FIX_2_POINTS(fix_word)); fix_word &= 0xfffff; while ( ( i-- != 0 ) && (fix_word != 0) ) { putc( (int)('0' + (FIX_2_POINTS(fix_word * 10))), fp); fix_word = (fix_word*10) & 0xfffff; } fputs(")\n", fp); } /************************************************************************/ /* */ /* do_ligatures( FILE * , CHARORDER * ) */ /* */ /* Routine to output the ligature lists */ /* For each ligature, PLtoTF expects the label of the first */ /* character, followed by a list of the ligatures it is used with */ /* */ /************************************************************************/ do_ligatures( fp , cur_order ) CHARORDER *cur_order; FILE *fp; { LIGTABLE *cur_lig; int second; int replace; int print_label; int label, j; unsigned short *gascii_base; /* start of gascii array */ unsigned short *g_ptr; /* gascii pointer */ gascii_base = cur_order->co_gascii; fputs("(LIGTABLE\n", fp); for ( label=0 ; labellig_first!= 0 ; cur_lig++ ) { if ( gascii_base[label] != cur_lig->lig_first ) continue; second = MAX_CHARS; replace = MAX_CHARS; for ( g_ptr=gascii_base,j=0 ; jlig_second ) second = j; if ( *g_ptr == cur_lig->lig_replace ) replace = j; } if ( second!=MAX_CHARS && replace!=MAX_CHARS ) { if ( print_label == 1 ) { print_label = 0; fprintf(fp, " (LABEL O %o)\n", label); } fprintf(fp, " (LIG O %o O %o)\n", second, replace); } } if ( print_label == 0 ) fprintf(fp, " (STOP)\n"); } fputs(" )\n", fp); } /************************************************************************/ /* */ /* read_res( FILE * ) */ /* */ /* Routine to input the resident font directory file. */ /* */ /************************************************************************/ read_res(fp) FILE *fp; { int c; char in_line[MAX_STRING]; char *input; char *start_char; int i; char map_file[MAX_FILENAME]; char comment[MAX_STRING]; while (TRUE) { input = in_line; while ( (c=getc(fp)) != '\n' ) { if ( c == EOF ) return; *input++ = c; } *input = '\0'; start_char = in_line; while ( (*start_char==' ') || (*start_char=='\t') ) start_char++; /* Blank line */ if ( start_char == input ) continue; /* Comment line */ if ( *start_char == '#' ) continue; if (sscanf(start_char, "%s%s%s", map_base[max_map].m_name, map_file, comment) < 2 ) { fprintf(stderr, "%s : Bad input line in file %s", pgm_name, res_file); fputs(in_line, stderr); exit(1); } for ( i=0 ; i %d\n", pgm_name, i); exit(1); } strcpy(order_map[i].co_file, map_file); read_map(map_file); } } } /************************************************************************/ /* */ /* read_map( char * ) */ /* */ /* Routine to read the character order map */ /* */ /************************************************************************/ read_map(file_name) char *file_name; { FILE *order_fp; /* file pointer for order file */ char order_name[MAX_FILENAME]; /* full filename */ char *input; /* current position of in_line */ char in_line[MAX_STRING]; /* inputted line of text */ char *start_char; /* first non-blank on line */ int c; /* inputted character */ int hi_gascii, lo_gascii; /* inputted gascii number */ int position; /* position of this gascii */ char comment[MAX_STRING]; /* comment portion of line */ sprintf(order_name, "%s/%s", res_dir, file_name); if ( (order_fp=fopen(order_name, "r")) == NULL ) { perror(order_name); exit(1); } while (TRUE) { input = in_line; while ( (c=getc(order_fp)) != '\n' ) { if ( c == EOF ) break; *input++ = c; } if ( c == EOF ) break; *input = '\0'; start_char = in_line; while ( (*start_char==' ') || (*start_char=='\t') ) start_char++; /* Blank line */ if ( start_char == input ) continue; /* Comment line */ if ( *start_char == '#' ) continue; /* Identifier string */ if ( *start_char == '=' ) { strcpy(order_map[max_order].co_id, (start_char+1)); continue; } if (sscanf(start_char, "%d.%d %d%s", &hi_gascii, &lo_gascii, &position, comment) < 3 ) { fprintf(stderr, "%s : Bad input line in file %s\n", pgm_name, order_name); fprintf(stderr, "\t`%s'\n", in_line); exit(1); } if ( (position>MAX_CHARS) || ( (long)(hi_gascii*256 + lo_gascii) > MAX_GASCII ) || ( hi_gascii*256 + lo_gascii ) < 0 ) { fprintf(stderr, "%s: Bad input line from file %s\n", pgm_name, order_name); fprintf(stderr, "\t`%s'\n", in_line); } else order_map[max_order].co_gascii[position] = hi_gascii*256 + lo_gascii; } max_order++; fclose(order_fp); }