/* SubFont ** ** This program makes new subfont which contains only selected characters. ** The program was started 27-Oct-1994 and began from source codes of the ** t1disasm and t1asm programs whose wroten by I. Lee Hetherington ** (ilh@lcs.mit.edu). ** ** Copyright (C) 1994, 1995, Basil K. Malyshev. All Rights Reserved. ** ** LIMITATIONS: ** This program can prepare only ATM compatible PS Type 1 fonts. ** In this reason you must download other type fonts avoiding this program. ** ** The reasons and applications of this program: ** 1. Some expert fonts have a lot of characters. For example EC/DC ** fonts are designed to cover most of european languages. ** However in each european language only few accented characters ** is used. This program can be used to make own smaller font ** which will be enought for typesetting in your language. ** 2. Together with psfstat.ps program distributed with this program ** you can organize partial font downloading. ** 3. Using this module as part of DVIPS program partial font ** downloading can be done faster. ** ** History: ** 27-Oct-94 Beginning ... ** 1-Nov-94 V1.0 First completly workable version. ** Works together with fload C-shell script which calls ** GhostScript with 'psfstat.ps' macroses to make ** map of required charactrs. ** 3-Nov-94 V1.1 Now can prepare fonts with non standard layout ** that have 'noaccess put' instead of '|' or 'NP'. ** Now can process HYBRID fonts which have two versions ** of the 'Subrs' for High and low resolution devices. ** That is many Oblique fonts (Univers, Helvetica, ...) ** 24-Nov-94 Uploaded to CTAN:fonts/utilities/fontload. ** 25-Nov-94 Fixed for VMS. ** 27-Nov-94 Add ability for the output without eexec that reduces ** size of output file and accelerates downloading process ** but not reduces required printer memory. ** 28-Nov-94 optimize Subrs construction, which slightly reduces ** memory requirements. ** Remove warning on unknown_15 code which is not documented ** by Adobe but used in blank characters. ** Enclose every font into mark ... cleartoark if ** Eexec_Output flag is off. ** 30-Nov-94 V1.2 Ported to MS-DOS, compiled by ** Microsoft (R) C/C++ Optimizing Compiler Version 8.0 ** 19-Dec-94 V1.3 Now can read font map in GhostScript format. ** So, SubFont and GhostScript can share the same font map. ** 7-Jan-95 V1.4 Fixed dcr10 encoding size problem. ** ******* Also, copyright of the t1asm and t1disasm programs is there: ******** ** ** Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. ** ** Permission is hereby granted to use, modify, and distribute this program ** for any purpose provided this copyright notice and the one below remain ** intact. ** ** author of the t1asm and t1disasm programs: ** I. Lee Hetherington (ilh@lcs.mit.edu) */ # define PROGRAM "SubFont" # define PROBLEM "BKM Type1 SubFont Extractor" # define VERSION "1.4" # define REVDATE "7-Jan-1995" # define AUTHOR "Basil K.Malyshev (Vassili Malychev)" # define COPYRIGHT "1994, 1995, Basil K. Malyshev." # include # include # include # include # ifdef MSDOS # define SMALL_MEMORY # define SYSID "MS-DOS" # define PATH_DELIMITER ';' # define FILE_DELIMITER '\\' # define DEFAULTFONTPATH ".;C:\\PSFONTS;C:\\GS;C:\\GS\\FONTS" # define RB "rb" # define WB "wb" # endif # ifdef vms # define SYSID "VMS" # define PATH_DELIMITER ',' # define FILE_DELIMITER 0 # define DEFAULTFONTPATH "SYS$DISK:[],Type1_Fonts:,GS_LIB:" # define RB "rb" # define WB "wb" # endif # ifdef unix # define SYSID "UNIX" # define PATH_DELIMITER ':' # define FILE_DELIMITER '/' # define DEFAULTFONTPATH ".:/usr/local/lib/Fonts" # define RB "r" # define WB "w" # endif # ifndef SYSID # define SMALL_MEMORY # define SYSID "(Assumed MS-DOS)" # define PATH_DELIMITER ';' # define FILE_DELIMITER '\\' # define DEFAULTFONTPATH ".;C:\\PSFONTS;C:\\GS;C:\\GS\\FONTS" # define RB "rb" # define WB "wb" # endif #define LINESIZE 4096 /* 256 */ typedef unsigned char byte; static int Verbose = 0; static int Trace = 0; static int ArrLosts = 0; static int TouchEncoding = 0; static int Eexec_Output = 1; static FILE *ifp /*VMS: = stdin */ ; static FILE *ofp /*VMS: = stdout */; static FILE *ufp = NULL; static char *uFileName = NULL; static char line[LINESIZE]; static int lenIV = 4; static char RD_String[] = "RD"; static char ND_String[] = "noaccess def"; static char NP_String[] = "noaccess put"; static struct { int code; char *name; } StdEnc[] = { 040 , "space", 041 , "exclam", 042 , "quotedbl", 043 , "numbersign", 044 , "dollar", 045 , "percent", 046 , "ampersand", 047 , "quoteright", 050 , "parenleft", 051 , "parenright", 052 , "asterisk", 053 , "plus", 054 , "comma", 055 , "hyphen", 056 , "period", 057 , "slash", 060 , "zero", 061 , "one", 062 , "two", 063 , "three", 064 , "four", 065 , "five", 066 , "six", 067 , "seven", 070 , "eight", 071 , "nine", 072 , "colon", 073 , "semicolon", 074 , "less", 075 , "equal", 076 , "greater", 077 , "question", 0100 , "at", 0101 , "A", 0102 , "B", 0103 , "C", 0104 , "D", 0105 , "E", 0106 , "F", 0107 , "G", 0110 , "H", 0111 , "I", 0112 , "J", 0113 , "K", 0114 , "L", 0115 , "M", 0116 , "N", 0117 , "O", 0120 , "P", 0121 , "Q", 0122 , "R", 0123 , "S", 0124 , "T", 0125 , "U", 0126 , "V", 0127 , "W", 0130 , "X", 0131 , "Y", 0132 , "Z", 0133 , "bracketleft", 0134 , "backslash", 0135 , "bracketright", 0136 , "asciicircum", 0137 , "underscore", 0140 , "quoteleft", 0141 , "a", 0142 , "b", 0143 , "c", 0144 , "d", 0145 , "e", 0146 , "f", 0147 , "g", 0150 , "h", 0151 , "i", 0152 , "j", 0153 , "k", 0154 , "l", 0155 , "m", 0156 , "n", 0157 , "o", 0160 , "p", 0161 , "q", 0162 , "r", 0163 , "s", 0164 , "t", 0165 , "u", 0166 , "v", 0167 , "w", 0170 , "x", 0171 , "y", 0172 , "z", 0173 , "braceleft", 0174 , "bar", 0175 , "braceright", 0176 , "asciitilde", 0241 , "exclamdown", 0242 , "cent", 0243 , "sterling", 0244 , "fraction", 0245 , "yen", 0246 , "florin", 0247 , "section", 0250 , "currency", 0251 , "quotesingle", 0252 , "quotedblleft", 0253 , "guillemotleft", 0254 , "guilsinglleft", 0255 , "guilsinglright", 0256 , "fi", 0257 , "fl", 0261 , "endash", 0262 , "dagger", 0263 , "daggerdbl", 0264 , "periodcentered", 0266 , "paragraph", 0267 , "bullet", 0270 , "quotesinglbase", 0271 , "quotedblbase", 0272 , "quotedblright", 0273 , "guillemotright", 0274 , "ellipsis", 0275 , "perthousand", 0277 , "questiondown", 0301 , "grave", 0302 , "acute", 0303 , "circumflex", 0304 , "tilde", 0305 , "macron", 0306 , "breve", 0307 , "dotaccent", 0310 , "dieresis", 0312 , "ring", 0313 , "cedilla", 0315 , "hungarumlaut", 0316 , "ogonek", 0317 , "caron", 0320 , "emdash", 0341 , "AE", 0343 , "ordfeminine", 0350 , "Lslash", 0351 , "Oslash", 0352 , "OE", 0353 , "ordmasculine", 0361 , "ae", 0365 , "dotlessi", 0370 , "lslash", 0371 , "oslash", 0372 , "oe", 0373 , "germandbls", 0, 0 }; static char *StandardEncoding[256]; void init_Encoding(void) { int i; for( i = 0 ; i < 256 ; i++ ) StandardEncoding[i] = NULL; for( i = 0 ; StdEnc[i].name != NULL ; i++ ) StandardEncoding[StdEnc[i].code] = StdEnc[i].name ; } static int Files = 0; /* Number of processed fonts */ void *xmalloc( int Size ) { void *ptr; if ( (ptr=malloc( Size )) == NULL ) { fprintf(stderr,"? SubFont: Not enought memory(needed %d bytes)\n",Size); exit(1); } return ptr; } char *xstrdup( char *str ) { char *ptr; ptr = xmalloc( strlen(str) + 1 ); strcpy(ptr,str); return ptr; } # define CHUNK_SIZE 128 struct ChunkSt { struct ChunkSt *next; void *ptr[CHUNK_SIZE]; } *currChunk = NULL, *next; static int currPtr = CHUNK_SIZE; void *fmalloc( int Size , char *tag ) { void *ptr; if ( (ptr=malloc( Size )) == NULL ) { fprintf(stderr,"? SubFont: Not enought memory for %s(needed %d bytes)\n", tag,Size); exit(1); } if ( currPtr >= CHUNK_SIZE ) { next = xmalloc( sizeof(struct ChunkSt) ); next->next = currChunk; currChunk = next; currPtr = 0; } currChunk->ptr[currPtr++] = ptr; return ptr; } void fAllFree( void ) /* Freeing all memory which was allocated by fmalloc */ { int j; long l; for( l = 0; currChunk != NULL; currChunk = next ) { next = currChunk->next; for( j = 0 ; j < currPtr ; j++,l++ ) free(currChunk->ptr[j]); free(currChunk); currPtr = CHUNK_SIZE; } if ( Verbose ) fprintf(stderr,"fAllFree(): Freeing %d memory blocks\n",l); } /* decryption stuff */ static unsigned short er, oer, cr; static unsigned short c1 = 52845, c2 = 22719; /* This function looks for `currentfile eexec' string and returns 1 once found. If c == 0, then simply check the status. */ static char *p_eexec_scan = 0; static int eexec_scanner( int /*char*/ c) { static char *key = "currentfile eexec\n"; if (!p_eexec_scan) p_eexec_scan = key; if (c && *p_eexec_scan) { if (c == *p_eexec_scan) ++p_eexec_scan; else p_eexec_scan = key; } return *p_eexec_scan == '\0'; } /* This function returns the value of a single hex digit. */ static int hexval(char c) { if (c >= 'A' && c <= 'F') return c - 'A' + 10; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; else if (c >= '0' && c <= '9') return c - '0'; else return 0; } /* This function returns a single character at a time from a PFA or PFB file. This stream is mixed ASCII and binary bytes. For PFB files, the section headers are removed, and \r is replaced by \n in ASCII sections. For PFA files, the hexdecimal data is turned into binary bytes. */ static int first_byte = 1; static int is_pfa = 0; static int is_pfb = 0; static long pfb_remaining = 0; static int bgetc() { int c, val; /* is_pfa == 1 means PFA initial ASCII section is_pfa == 2 means PFA hexadecimal section is_pfb == 1 means PFB ASCII section is_pfB == 2 means PFB binary section */ c = fgetc(ifp); if (c == EOF) return EOF; if (first_byte) { /* Determine if this is a PFA or PFB file by looking at first byte. */ if (c == 0x80) { is_pfb = 1; is_pfa = 0; } else { is_pfb = 0; is_pfa = 1; } first_byte = 0; } if (is_pfb) { /* PFB */ if (pfb_remaining == 0) { /* beginning of block---we know c == 0x80 at this point */ switch (fgetc(ifp)) { case 1: is_pfb = 1; break; case 2: is_pfb = 2; break; case 3: return EOF; default: fprintf(stderr, "error: is this really a PFB file?\n"); exit(1); } /* get block length */ pfb_remaining = (long)fgetc(ifp) & 0xff; pfb_remaining |= ((long)fgetc(ifp) & 0xff) << 8; pfb_remaining |= ((long)fgetc(ifp) & 0xff) << 16; pfb_remaining |= ((long)fgetc(ifp) & 0xff) << 24; /* get character */ c = fgetc(ifp); if (c == EOF) return EOF; } --pfb_remaining; /* in ASCII section change return to newline */ if (is_pfb == 1 && c == '\r') c = '\n'; (void)eexec_scanner(c); return c; } else { /* PFA */ if (is_pfa == 1) { /* in initial ASCII */ if (eexec_scanner(c)) is_pfa = 2; return c; } else { /* in hexadecimal */ while (isspace(c)) c = fgetc(ifp); val = hexval((char)c) << 4; val |= hexval((char)(c = fgetc(ifp))); if (c == EOF) return EOF; return val; } } } /* Two separate decryption functions because eexec and charstring decryption must proceed in parallel. */ static byte edecrypt(int /*byte */ cipher) { byte plain; plain = (byte)(cipher ^ (er >> 8)); er = (cipher + er) * c1 + c2; return plain; } static byte cdecrypt( int /*byte*/ cipher) { byte plain; plain = (byte)(cipher ^ (cr >> 8)); cr = (cipher + cr) * c1 + c2; return plain; } /* This function returns 1 the first time the eexec_scanner returns 1. */ static int reported = 0; static int immediate_eexec() { if (!reported && eexec_scanner(0)) { reported = 1; return 1; } else { return 0; } } /* This function returns a single byte at a time through (possible) eexec decryption. When immediate_eexec returns 1 it fires up the eexec decryption machinery. */ static int in_eexec = 0, out_eexec = 0; static int egetc() { int c,j; if ((c = bgetc()) == EOF) return EOF; if (!in_eexec) { if (immediate_eexec()) { /* start eexec decryption */ in_eexec = 1; er = 55665; /* toss out four random bytes */ for( j = 4 ; j > 0 ; j-- ) (void) edecrypt(bgetc()); } return c; } else { return edecrypt(c); } } /* This function returns a line of eexec decrypted characters. A line is terminated by length (including terminating null) greater than LINESIZE, a newline \n, or one of the special charstring start sequences ` -| ' or ` RD '. The line, including the terminating newline or charstring start sequence is put into line[]. If terminated by a charstring start sequence, the flag start_charstring is set to 1. */ static int egetline() { int c,cnt,cntcont; char *p = line; cnt = 0; cntcont = 0; while (p < line + LINESIZE) { c = egetc(); if (c == EOF) break; if ( '0' <= c && c <= '9' ) { cnt = ( cntcont ? cnt * 10 : 0 ) + c - '0' ; cntcont = 1; } else cntcont = 0; *p++ = (char) c; if (p >= line + 4 && (strncmp(p - 4, " -| ", 4) == 0 || strncmp(p - 4, " RD ", 4) == 0)) { for( ; cnt >= 0 ; cnt-- ) *p++ = (char)egetc(); /* load char string */ } if (c == '\r') { /* map \r to \n */ p[-1] = '\n'; break; } if (c == '\n') break; } *p = '\0'; return (int)(p-line); } /* If the line contains an entry of the form `/lenIV ' then set the global lenIV to . This indicates the number of random bytes at the beginning of each charstring. */ static void set_lenIV() { char *p = strstr(line, "/lenIV "); if (p && isdigit(p[7])) { lenIV = atoi(p + 7); } } /* Subroutine to output strings. */ # define MAXPOOL 8192 static char *pool[MAXPOOL]; static int pool_cnt = 0; static void output(char *string) { if ( pool_cnt >= MAXPOOL ) { fprintf(stderr,"Not enought pool size...\n"); exit(1); } pool[pool_cnt] = fmalloc( strlen(string) + 1 , "output buffer line" ); strcpy(pool[pool_cnt],string); pool_cnt++; } /************************** Output routines .... ************************/ # define SMALL_MEMORY #ifdef SMALL_MEMORY #define MAXBLOCKLEN 32000 #else #define MAXBLOCKLEN ((1<<17)-6) #endif #define MINBLOCKLEN ((1<<8)-6) #define MARKER 128 #define ASCII 1 #define BINARY 2 #define DONE 3 /* flags */ static int pfb = 0; static int active = 0; /* static int in_eexec = 0; File firstly loaded and then dumped ... */ /* for PFB block buffering */ static byte blockbuf[MAXBLOCKLEN]; static int blocklen = MAXBLOCKLEN; static int blockpos = -1; static int blocktyp = ASCII; static byte eencrypt( byte plain) { byte cipher; cipher = (byte)(plain ^ (oer >> 8)); oer = (cipher + oer) * c1 + c2; return cipher; } /* This function flushes a buffered PFB block. */ static void output_block() { int i; /* output four-byte block length */ fputc(blockpos & 0xff, ofp); fputc((blockpos >> 8) & 0xff, ofp); fputc((blockpos >> 16) & 0xff, ofp); fputc((blockpos >> 24) & 0xff, ofp); /* output block data */ for (i = 0; i < blockpos; i++) fputc(blockbuf[i], ofp); /* mark block buffer empty and uninitialized */ blockpos = -1; } /* This function outputs a single byte. If output is in PFB format then output is buffered through blockbuf[]. If output is in PFA format, then output will be hexadecimal if in_eexec is set, ASCII otherwise. */ static int hexcol = 0 ; static void output_byte(byte b) { static char *hexchar = "0123456789ABCDEF"; if (pfb) { /* PFB */ if (blockpos < 0) { fputc(MARKER, ofp); fputc(blocktyp, ofp); blockpos = 0; } blockbuf[blockpos++] = b; if (blockpos == blocklen) output_block(); } else { /* PFA */ if (out_eexec) { /* trim hexadecimal lines to 64 columns */ if (hexcol >= 64) { fputc('\n', ofp); hexcol = 0; } fputc(hexchar[(b >> 4) & 0xf], ofp); fputc(hexchar[b & 0xf], ofp); hexcol += 2; } else { fputc(b, ofp); } } } /* This function outputs a byte through possible eexec encryption. */ static void eexec_byte(byte b) { if (out_eexec) output_byte(eencrypt(b)); else output_byte(b); } /* This function outputs a null-terminated string through possible eexec encryption. */ static void eexec_string(char *string) { while (*string) eexec_byte((byte) *string++); } /* This function gets ready for the eexec-encrypted data. If output is in PFB format then flush current ASCII block and get ready for binary block. We start encryption with four random (zero) bytes. */ static void eexec_start() { if (pfb) { output_block(); blocktyp = BINARY; } out_eexec = 1; oer = 55665; eexec_byte('B'); eexec_byte('K'); eexec_byte('M'); eexec_byte('!'); } /* This function wraps-up the eexec-encrypted data and writes ASCII trailer. If output is in PFB format then this entails flushing binary block and starting an ASCII block. */ static void eexec_end() { int i, j; if (pfb) { output_block(); blocktyp = ASCII; } else { fputc('\n', ofp); } out_eexec = 0; for (i = 0; i < 8; i++) { for (j = 0; j < 64; j++) eexec_byte('0'); eexec_byte('\n'); } eexec_string("cleartomark\n"); if (pfb) { output_block(); fputc(MARKER, ofp); fputc(DONE, ofp); } } static void Dump_Pool( int from , int to ) { int i; for ( i = from ; i < to ; i++ ) { if ( Eexec_Output ) { eexec_string(pool[i]); if ( strcmp(pool[i], "currentfile eexec\n") == 0 ) eexec_start(); } else { if ( i == 0 ) eexec_string("mark %%\n"); if( strcmp(pool[i], "mark currentfile closefile\n") == 0 ) eexec_string("end cleartomark%%\n"); else if ( strcmp(pool[i], "currentfile eexec\n") == 0 ) eexec_string("systemdict begin\n"); else eexec_string(pool[i]); } } } static void Dump_CS( int Len , unsigned char *cs ) { if ( Eexec_Output ) { char buf[64]; sprintf(buf," %d %s ", Len, RD_String); eexec_string(buf); for( ; Len > 0 ; Len--, cs++) eexec_byte(*cs); eexec_byte(' '); } else { int c; eexec_string("\n<"); for( c = 2 ; Len > 0 ; Len--, cs++, c += 2) { eexec_byte("0123456789ABCDEF"[((*cs)>>4)&0xF]); eexec_byte("0123456789ABCDEF"[(*cs)&0xF]); if ( c > 70 ) { eexec_byte('\n'); c = 0; } } eexec_string("> "); } } int Subrs = 0; int MaxSubrs = 0; int SubrsPosition = 0; int HiSubrs = 0; int HiMaxSubrs = 0; int HiSubrsPosition = 0; typedef struct { unsigned char *cs; int len; int use; /* Using marker ... */ } CSType; CSType *Subr, *HiSubr; int CharStrings = 0; int CharStringsPosition = 0; struct { char *Name; unsigned char *cs; int len; int use; /* Using marker */ } *CharString; int CharStringCnt = 0; static int sp, stack[128]; static int cop, vop[32]; void ProcessCharString( unsigned char *cs , int len ) { int p, i, b, val; unsigned short cr_save ; cr_save = cr; cr = 4330; for (p = 0; p < len && p < lenIV; p++ ) cdecrypt(cs[p]); while ( p < len ) { b = cdecrypt(cs[p++]); if (b >= 32) { if (b >= 32 && b <= 246) val = b - 139; else if (b >= 247 && b <= 250) val = (b - 247)*256 + 108 + cdecrypt(cs[p++]); else if (b >= 251 && b <= 254) val = -(b - 251)*256 - 108 - cdecrypt(cs[p++]); else if (b == 255) { val = (cdecrypt(cs[p++]) & 0xff) << 24; val |= (cdecrypt(cs[p++]) & 0xff) << 16; val |= (cdecrypt(cs[p++]) & 0xff) << 8; val |= (cdecrypt(cs[p++]) & 0xff) << 0; /* in case an int is larger than four bytes---sign extend */ if (sizeof(int) > 4 && val & (1U << 31)) for (i = 4; i < sizeof(int); i++) val |= 0xff << (i * 8); } stack[sp++] = val; } else { if ( Trace ) fprintf(stderr,"[%d]",b); switch (b) { case 1: sp = 0; /* ("hstem"); */ break; case 3: sp = 0; /* ("vstem"); */ break; case 4: sp = 0; /* ("vmoveto"); */ break; case 5: sp = 0; /* ("rlineto"); */ break; case 6: sp = 0; /* ("hlineto"); */ break; case 7: sp = 0; /* ("vlineto"); */ break; case 8: sp = 0; /* ("rrcurveto"); */ break; case 9: sp = 0; /* ("closepath"); */ break; case 10: /* ("callsubr"); */ val = stack[--sp]; if ( ! ( 0 <= val && val < MaxSubrs ) ) { fprintf(stderr,"Illegal call of unexistant subroutine %d\n",val); exit(1); } if ( Trace ) fprintf(stderr,"{%d:",val); /* if ( ! Subr[val].use ) */ { /* Process it, if yet not processed ... */ CSType *SvSubr; SvSubr = HiSubr; HiSubr = NULL; Subr[val].use = 1; ProcessCharString( Subr[val].cs , Subr[val].len ); HiSubr = SvSubr; } if ( HiSubr != NULL ) { /* Process it, if yet not processed ... */ CSType *SvSubr; SvSubr = Subr; Subr = HiSubr; HiSubr = NULL; Subr[val].use = 1; ProcessCharString( Subr[val].cs , Subr[val].len ); HiSubr = Subr; Subr = SvSubr; } if ( Trace ) fprintf(stderr,"}"); break; case 11: /* ("return"); */ cr = cr_save; return; case 13: sp = 0; /* ("hsbw"); */ break; case 14: sp = 0; /* ("endchar"); */ break; case 15: sp = 0; /* Undocumented code but used in blank characters */ break; case 21: sp = 0; /* ("rmoveto"); */ break; case 22: sp = 0; /* ("hmoveto"); */ break; case 30: sp = 0; /* ("vhcurveto"); */ break; case 31: sp = 0; /* ("hvcurveto"); */ break; case 12: b = cdecrypt(cs[p++]) ; if ( Trace ) fprintf(stderr,"[%d]",b); switch (b) { case 0: sp = 0; /* ("dotsection"); */ break; case 1: sp = 0; /* ("vstem3"); */ break; case 2: sp = 0; /* ("hstem3"); */ break; case 6: /* ("seac"); */ { int c1,c2; c1 = stack[--sp]; c2 = stack[--sp]; sp -= 3; if ( StandardEncoding[c1] == NULL ) fprintf(stderr,"No character %d in Standard encoding\n",c1); else { for( i = 0 ; i < CharStringCnt ; i++ ) if ( ! strcmp(CharString[i].Name+1,StandardEncoding[c1]) ) break; if ( i >= CharStringCnt ) fprintf(stderr,"No seac refered character %s in font\n", StandardEncoding[c1]); else if ( ! CharString[i].use ) { CharString[i].use = 1; sp = 0; ProcessCharString( CharString[i].cs , CharString[i].len ); } } c1 = c2; if ( StandardEncoding[c1] == NULL ) fprintf(stderr,"No character %d in Standard encoding\n",c1); else { for( i = 0 ; i < CharStringCnt ; i++ ) if ( ! strcmp(CharString[i].Name+1,StandardEncoding[c1]) ) break; if ( i >= CharStringCnt ) fprintf(stderr,"No seac refered character %s in font\n", StandardEncoding[c1]); else if ( ! CharString[i].use ) { CharString[i].use = 1; sp = 0; ProcessCharString( CharString[i].cs , CharString[i].len ); } } } break; case 7: sp = 0; /* ("sbw"); */ break; case 12: sp--; stack[sp-1] /= stack[sp]; /* ("div"); */ break; case 16: /* ("callothersubr"); */ /* I have no Adobe Type 1 manual on hands now and not remember order of loading arguments in calling of othersubr but there it is not important. */ val = stack[--sp]; cop = stack[--sp]; for( i = 0 ; i < cop ; i++ ) vop[i] = stack[--sp]; /* Special logic there ... */ if ( val == 3 ) Subr[3].use = 1; /* Used hint replacement */ break; case 17: /* ("pop"); */ stack[sp++] = vop[--cop]; break; case 33: sp -= 2; /* sp = 0; */ /* ("setcurrentpoint"); */ break; default: fprintf(stderr, "UNKNOWN_12_%d", b); break; } break; default: fprintf(stderr, "UNKNOWN_%d", b); break; } } } /* End while */ cr = cr_save; } void Fix_String( char *dst , char *Tag , int Val , char *src ) { char *cp,*dp; strcpy(dst,src); if ( (cp=strstr(src,Tag)) == NULL ) { fprintf(stderr,"Nu i nu, not '%s' in '%s'\n",Tag,src); exit(1); } cp += strlen(Tag); dp = dst + (cp-src); while ( *cp && *cp <= ' ' ) cp++; /* skip spaces */ while ( '0' <= *cp && *cp <= '9' ) cp++; /* skip digits */ sprintf(dp,"%d%s",Val,cp); } # define MAXENCODINGS 64 int EncodingPosition = 0; # ifdef PEDANTICAL_ENCODING_PROCESSING char **Encoding = 0; int EncodingCnt = 0; char **EncodingList[MAXENCODINGS]; char *RegisterEncoding( char **Encoding ) { int i,j; static char buf[64]; /* Search the same encoding ... */ for( i = 0 ; i < EncodingCnt ; i++ ) { for( j = 0 ; j < 256 ; j++ ) if ( strcmp(Encoding[j],EncodingList[i][j]) ) break; if ( j >= 256 ) break; /* Found the same encoding ... */ } if ( i >= EncodingCnt ) { /* Booking new encoding ... */ if ( EncodingCnt < MAXENCODINGS ) EncodingList[EncodingCnt++] = Encoding; else fprintf(stderr,"Too many different encodings...\n"); /* Write this Encoding into file ... */ fprintf(ofp,"/SubFontEncoding-%d 256 array\n",i); fprintf(ofp,"0 1 255 {1 index exch /.notdef put} for\n"); for( j = 0 ; j < 256 ; j++ ) if ( strcmp(Encoding[j],"/.notdef") ) fprintf(ofp,"dup %d %s put\n",j,Encoding[j]); fprintf(ofp,"readonly def\n"); } sprintf(buf,"SubFontEncoding-%d",i); return buf; } void Begin_Encoding( char *line ) { int i; Encoding = xmalloc( 256 * sizeof(char *) ); for( i = 0; i < 256 ; i++ ) Encoding[i] = "/.notdef"; } int Fill_Encoding( char *line ) { int IsEncoding ; char *cp,buf[128]; IsEncoding = 1; if ( (cp=strstr(line," def")) != NULL ) /* End of encoding vector */ { char *EncName, buf[128]; IsEncoding = 0; EncName = RegisterEncoding( Encoding ); sprintf(buf,"/Encoding %s def\n",EncName); pool_cnt--; /* discard previos Encoding line */ if ( Verbose ) fprintf(stderr,"End of encoding vector at: %s by %s",line,cp); output(buf); /* make reference into our encoding ... */ } else if ( (cp=strstr(line,"dup ")) != NULL ) { /* Fill encoding vector by follow material ... */ int code; char *ep; while ( (cp=strstr(cp,"dup ")) != NULL ) { cp += 4; code = atoi(cp); if ( code < 0 || code >= 256 ) { fprintf(stderr,"Invalid encoding '%s'\n",line); exit(1); } while( *cp && *cp <= ' ' ) cp++; while( *cp && '0' <= *cp && *cp <= '9' ) cp++; while( *cp && *cp <= ' ' ) cp++; if ( *cp != '/' ) { fprintf(stderr,"Invalid encoding '%s'\n",line); exit(1); } for( ep = cp ; *ep && *ep > ' ' ; ep++ ); Encoding[code] = xmalloc( (ep-cp) + 1 ); memcpy(Encoding[code],cp,ep-cp); Encoding[code][ep-cp] = 0; } } return IsEncoding; } # else # define MAXENCODINGLINES 512 /* Must be more then 256, for example dcr... */ int EncodingLines = 0; char *Encoding[MAXENCODINGLINES]; int EncodingCnt = 0; struct { char **Body; int Lines; } EncodingList[MAXENCODINGS]; char *RegisterEncoding( char **Encoding ) { int i,j; static char buf[64]; /* Search the same encoding ... */ for( i = 0 ; i < EncodingCnt ; i++ ) if ( EncodingList[i].Lines == EncodingLines ) { for( j = 0 ; j < EncodingList[i].Lines ; j++ ) if ( strcmp(Encoding[j],EncodingList[i].Body[j]) ) break; if ( j >= EncodingList[i].Lines ) break; /* the same encoding ... */ } if ( i >= EncodingCnt ) { /* Booking new encoding ... */ if ( EncodingCnt < MAXENCODINGS ) { EncodingList[EncodingCnt].Lines = EncodingLines ; EncodingList[EncodingCnt].Body = xmalloc( sizeof(char *) * EncodingLines ); memcpy(EncodingList[EncodingCnt].Body,Encoding, sizeof(char *) * EncodingLines ); EncodingCnt++; } else fprintf(stderr,"Too many different encodings...\n"); /* Write this Encoding into file ... */ for( j = 0 ; j < EncodingLines ; j++ ) fputs(Encoding[j],ofp); fprintf(ofp,"/SubFontEncoding-%d Encoding def\n",i); } sprintf(buf,"SubFontEncoding-%d",i); return buf; } void Begin_Encoding( char *line ) { EncodingLines = 0; Encoding[EncodingLines++] = xstrdup(line); } int Fill_Encoding( char *line ) { int IsEncoding ; char *cp; IsEncoding = 1; if ( EncodingLines >= MAXENCODINGLINES ) { fprintf(stderr,"? SubFont: Too long encoding\n"); exit(1); } Encoding[EncodingLines++] = xstrdup(line); if ( (cp=strstr(line," def")) != NULL ) /* End of encoding vector */ { char *EncName, buf[128]; EncName = RegisterEncoding( Encoding ); sprintf(buf,"/Encoding %s def\n",EncName); pool_cnt--; /* discard previos Encoding line */ if ( Verbose ) fprintf(stderr,"End of encoding vector at: %s by %s",line,cp); output(buf); /* make reference into our encoding ... */ return 0; } return 1; } # endif int Process_Font( char *NeedChars ) { int i,k,l; int IsEncoding; /* reset important variables ... */ Subrs = 0; MaxSubrs = 0; SubrsPosition = 0; HiMaxSubrs = 0; HiSubrsPosition = 0; Subr = HiSubr = NULL; CharStrings = 0; CharStringsPosition = 0; CharStringCnt = 0; lenIV = 4; first_byte = 1; is_pfa = is_pfb = 0; pfb_remaining = 0; p_eexec_scan = 0; reported = 0; in_eexec = out_eexec = 0; pool_cnt = 0; EncodingPosition = 0; /* Encoding = NULL; */ IsEncoding = 0; hexcol = 0; /* main loop---normally done when reach `mark currentfile closefile' on output (rest is garbage). */ for (;;) { egetline(); if (line[0] == '\0') break; set_lenIV(); if ( IsEncoding ) { IsEncoding = Fill_Encoding( line ); } else if ( Subrs ) { int SubrNo; char *cp; for( cp = line ; *cp && *cp <= ' ' ; cp++ ); if ( strncmp(cp,"dup ",4) != 0 ) { fprintf(stderr,"Unexpected end of Subrs: '%s'",line); fprintf(stderr,"While %d Subrs yet not defined\n",Subrs); Subrs = 0; } else { cp += 4; while( *cp && *cp <= ' ' ) cp++; /* skip leader spaces */ SubrNo = atoi(cp); if ( SubrNo < 0 || SubrNo >= MaxSubrs ) { fprintf(stderr,"Invalid subr number %d\n",SubrNo); exit(1); } while( '0' <= *cp && *cp <= '9' ) cp++; /* skip digits */ while( *cp && *cp <= ' ' ) cp++; /* skip spaces */ Subr[SubrNo].len = atoi(cp); while( '0' <= *cp && *cp <= '9' ) cp++; /* skip digits */ while( *cp && *cp <= ' ' ) cp++; /* skip spaces */ if ( ! ( ( cp[0] == 'R' && cp[1] == 'D' && cp[2] == ' ' ) || ( cp[0] == '-' && cp[1] == '|' && cp[2] == ' ' ) ) ) { fprintf(stderr,"Bad CharString: %s",cp); exit(1); } if ( cp[0] == 'R' && cp[1] == 'D' ) strcpy(RD_String,"RD"); if ( cp[0] == '-' && cp[1] == '|' ) strcpy(RD_String,"-|"); cp += 3 ; Subr[SubrNo].cs = fmalloc( Subr[SubrNo].len + 1 , "Subrs" ); memcpy(Subr[SubrNo].cs,cp,Subr[SubrNo].len ); Subr[SubrNo].cs[Subr[SubrNo].len] = 0; cp += Subr[SubrNo].len ; while( *cp && *cp <= ' ' ) cp++; /* skip spaces */ if ( cp[0] == 'N' && cp[1] == 'P' ) strcpy(NP_String,"NP"); else if ( cp[0] == '|' ) strcpy(NP_String,"|"); else if ( strncmp(cp,"noaccess put",12) == 0 ) strcpy(NP_String,"noaccess put"); else if ( strncmp(cp,"readonly put",12) == 0 ) strcpy(NP_String,"readonly put"); else { fprintf(stderr,"Bad CharString: %s",cp); exit(1); } if ( Trace ) fprintf(stderr,"[%d,%d]",SubrNo,Subr[SubrNo].len); Subrs--; } } else if ( CharStrings ) { char *cp; if ( line[0] != '/' ) { fprintf(stderr,"Unexpected end of CharStrings: '%s'",line); fprintf(stderr,"While %d CharStrings yet not defined\n",Subrs); CharStrings = 0; } else { cp = line; while( *cp && *cp > ' ' ) cp++; /* Skip name */ *cp++ = 0; CharString[CharStringCnt].Name = fmalloc(strlen(line)+1,line); strcpy(CharString[CharStringCnt].Name, line ); if ( Trace ) fprintf(stderr,"%s",line); while( *cp && *cp <= ' ' ) cp++; /* Skip spaces ... */ CharString[CharStringCnt].len = atoi(cp); while( '0' <= *cp && *cp <= '9' ) cp++; /* skip digits */ while( *cp && *cp <= ' ' ) cp++; /* skip spaces */ if ( ! ( ( cp[0] == 'R' && cp[1] == 'D' && cp[2] == ' ' ) || ( cp[0] == '-' && cp[1] == '|' && cp[2] == ' ' ) ) ) { fprintf(stderr,"Bad CharString: %s",cp); exit(1); } if ( cp[0] == 'R' && cp[1] == 'D' ) strcpy(RD_String,"RD"); if ( cp[0] == '-' && cp[1] == '|' ) strcpy(RD_String,"-|"); cp += 3 ; CharString[CharStringCnt].cs = fmalloc( CharString[CharStringCnt].len , "CharString" ); memcpy(CharString[CharStringCnt].cs,cp, CharString[CharStringCnt].len ); cp += CharString[CharStringCnt].len ; while( *cp && *cp <= ' ' ) cp++; /* skip spaces */ if ( cp[0] == 'N' && cp[1] == 'D' ) strcpy(ND_String,"ND"); else if ( cp[0] == '|' && cp[1] == '-' ) strcpy(ND_String,"|-"); else if ( strncmp(cp,"noaccess def",12) == 0 ) strcpy(ND_String,"noaccess def"); else if ( strncmp(cp,"readonly def",12) == 0 ) strcpy(ND_String,"readonly def"); else { fprintf(stderr,"Bad CharString: %s",cp); exit(1); } CharStringCnt++; CharStrings--; } } else { char *cp; if ( (cp=strstr(line,"/Subrs ")) != NULL ) { /* Start of subrs there ... */ if ( SubrsPosition ) { /* HYBRID Type1 fonts have two copies of Subrs, for High and low resolution devices. There I will save previously accumulated Subrs ... */ HiMaxSubrs = MaxSubrs; HiSubrsPosition = SubrsPosition; HiSubr = Subr; } /* Temporarie, fragments only first copy of Subrs... */ cp += strlen("/Subrs "); MaxSubrs = Subrs = atoi(cp); if ( Verbose ) fprintf(stderr,"Declared %d in Subrs\n",Subrs); SubrsPosition = pool_cnt ; Subr = fmalloc( Subrs * sizeof(*Subr) , "Subr array" ); } else if ( (cp=strstr(line,"/CharStrings ")) != NULL ) { /* Start of CharStrings there ... */ if ( ! CharStringsPosition ) { /* Only first appearing of /CharStrings indicate real CS */ cp += strlen("/CharStrings "); CharStrings = atoi(cp); if ( Verbose ) fprintf(stderr,"Declared %d in CharStrings\n",CharStrings); CharStringsPosition = pool_cnt ; CharString = fmalloc( CharStrings * sizeof(*CharString) , "CharString array" ); CharStringCnt = 0; } } else if ( TouchEncoding && (cp=strstr(line,"/Encoding ")) == line ) { if ( (cp=strstr(line,"def")) == NULL ) { EncodingPosition = pool_cnt; IsEncoding = 1; Begin_Encoding( line ); } } output(line); } if (strcmp(line, "mark currentfile closefile\n") == 0) break; } if ( Verbose ) fprintf(stderr,"Loaded %d lines\n",pool_cnt); /* Mark ONLY required charstrings ... */ /* Clear all use markers */ for( i = 0 ; i < MaxSubrs ; i++ ) Subr[i].use = 0; if ( HiSubr != NULL ) for( i = 0 ; i < HiMaxSubrs ; i++ ) HiSubr[i].use = 0; for( i = 0 ; i < CharStringCnt ; i++ ) CharString[i].use = 0; /* Walk Throught Charstrings and mark all used ones. */ for( i = 0 ; i < CharStringCnt ; i++ ) { char buf[128]; sprintf(buf,"%s/",CharString[i].Name); if ( strcmp(buf,"/.notdef/") == 0 || strstr(NeedChars,buf) != NULL ) { CharString[i].use = 1; sp = 0; if ( Trace ) fprintf(stderr,"<%s",buf); ProcessCharString( CharString[i].cs , CharString[i].len ); if ( Trace ) fprintf(stderr,">"); } } /* Simplest variant; replace unused charstrings by shortenest ... */ l = 0; for ( i = 0 , k = 0 ; i < MaxSubrs ; i++ ) if ( ! Subr[i].use ) { Subr[i] = Subr[3]; Subr[i].use = 0; } else { k = i; l++; } MaxSubrs = k+1; /* Forget tail of unused subrs ... */ if ( HiSubr != NULL ) { for ( i = 0 , k = 0 ; i < HiMaxSubrs ; i++ ) if ( ! HiSubr[i].use ) { HiSubr[i] = HiSubr[3]; HiSubr[i].use = 0; } else { k = i; l++; } HiMaxSubrs = k+1; /* Forget tail of unused subrs ... */ } l = MaxSubrs + (HiSubr == NULL ? 0 : HiMaxSubrs) - l; if ( Verbose ) fprintf(stderr,"%d empty array positions\n",l); ArrLosts += l * 8; /* Now dumps all my fragments ... */ in_eexec = out_eexec = 0; if ( SubrsPosition ) { if ( HiSubrsPosition ) { Dump_Pool( 0 , HiSubrsPosition) ; if ( HiMaxSubrs > 0 ) /* Can be removed all after filtering ... */ { /* Dump Subrs there ... */ Fix_String( line , "/Subrs " , HiMaxSubrs , pool[HiSubrsPosition] ); eexec_string(line); for( i = 0 ; i < HiMaxSubrs ; i++ ) { if ( (!Eexec_Output) && (!HiSubr[i].use) ) continue; sprintf(line,"dup %d",i); eexec_string(line); Dump_CS(HiSubr[i].len,HiSubr[i].cs); sprintf(line,"%s\n",NP_String); eexec_string(line); } Dump_Pool( HiSubrsPosition+1, SubrsPosition ) ; } else Dump_Pool( HiSubrsPosition+2 , SubrsPosition) ; } else Dump_Pool( 0 , SubrsPosition) ; if ( MaxSubrs > 0 ) /* Can be removed all after filtering ... */ { /* Dump Subrs there ... */ Fix_String( line , "/Subrs " , MaxSubrs , pool[SubrsPosition] ); eexec_string(line); for( i = 0 ; i < MaxSubrs ; i++ ) { if ( (!Eexec_Output) && (!Subr[i].use) ) continue; sprintf(line,"dup %d", i); eexec_string(line); Dump_CS(Subr[i].len,Subr[i].cs); sprintf(line,"%s\n",NP_String); eexec_string(line); } Dump_Pool( SubrsPosition+1, CharStringsPosition ) ; } else Dump_Pool( SubrsPosition+2, CharStringsPosition ) ; } else Dump_Pool( 0, CharStringsPosition ) ; for( i = k = 0 ; i < CharStringCnt ; i++ ) if ( CharString[i].use ) k++; Fix_String( line , "/CharStrings " , k , pool[CharStringsPosition] ); eexec_string(line); for( i = k = 0 ; i < CharStringCnt ; i++ ) if ( CharString[i].use ) { eexec_string(CharString[i].Name); Dump_CS(CharString[i].len, CharString[i].cs ); sprintf(line,"%s\n",ND_String); eexec_string(line); } Dump_Pool( CharStringsPosition+1 , pool_cnt ) ; if ( out_eexec ) eexec_end(); else if ( Eexec_Output ) fprintf(stderr,"? Strange font format (without eexec...)\n"); fAllFree(); return 0; } Copying_Full_Font(void) { int i, cnt; lenIV = 4; first_byte = 1; is_pfa = is_pfb = 0; pfb_remaining = 0; p_eexec_scan = 0; reported = 0; in_eexec = out_eexec = 0; hexcol = 0; while ( 1 ) { cnt = egetline(); if ( line[0] == 0 ) break; set_lenIV(); for( i = 0 ; i < cnt ; i++ ) eexec_byte(line[i]); if (strcmp(line, "mark currentfile closefile\n") == 0) break; if ( in_eexec && (!out_eexec) ) eexec_start(); } if ( out_eexec ) eexec_end(); else fprintf(stderr,"This font is not an ATM compatible, eexec is missed\n"); return 0; } FILE *Set_Adequate_Read_Mode( FILE *fp , char *fileName ) /* 25-Nov-94 I can not correctly read text file which was opened as binary in VMS. In this reason, if opened file is not PFB i will reopen it in text mode. */ { # if defined(vms) || defined(MSDOS) if ( fgetc(fp) == MARKER ) ungetc(MARKER,fp); else { fclose(fp); if ( (fp=fopen(fileName,"r")) == NULL ) { fprintf(stderr,"Ops, can't reopen file %s\n",fileName); exit(1); } } # endif return fp; } Scan_FontName( char *fileName , FILE *fp ) { int cnt; lenIV = 4; first_byte = 1; is_pfa = is_pfb = 0; pfb_remaining = 0; p_eexec_scan = 0; reported = 0; in_eexec = out_eexec = 0; hexcol = 0; if ( (ifp=fopen(fileName,RB)) == NULL ) { fprintf(stderr,"? Can't found file %s\n",fileName); return 0; } ifp = Set_Adequate_Read_Mode( ifp , fileName ); while ( 1 ) { cnt = egetline(); if ( line[0] == 0 ) break; set_lenIV(); if( strncmp(line,"/FontName",9) == 0 ) { char *cp,*ep; for( cp = line + 9 ; *cp && *cp <= ' ' ; cp++ ); for( ep = cp ; *ep && *ep > ' ' ; ep++ ); *ep = '\0'; fprintf(fp,"%s (%s) ;\n",cp,fileName); fclose(ifp); return 1; } } fclose(ifp); return 0; } struct FontMap { struct FontMap *next; char *fontName; char *fileName; } *fmp, *fontMap = NULL; int main(int ac, char **av) { int ap; char *cp; char *Need_Chars = NULL; char *FontSearchPath = DEFAULTFONTPATH ; FILE *fp; char buf[4096]; ifp = stdin; ofp = stdout; init_Encoding(); for( ap = 1 ; ap < ac ; ap++ ) if ( av[ap][0] == '-' && av[ap][1] != 0 ) switch( av[ap][1] ) { case 'v': case 'V': /* Like trace verbose */ Verbose = 1; break; case 't': case 'T': /* Trace font processing */ Trace = 1; break; case 'e': case 'E': /* Encoding optimization falg */ TouchEncoding = atoi(av[ap]+2); break; case 'x': case 'X': /* output eexec using flag */ Eexec_Output = atoi(av[ap]+2); break; case 'o': case 'O': /* ... Open output file there */ cp = av[ap][2] ? av[ap]+2 : av[++ap] ; if ( (ofp=fopen(cp,"w")) == NULL ) { fprintf(stderr,"? Can't create file: '%s'\n",cp); return 1; } break; case 'a': case 'A': /* ... Open output file for append */ cp = av[ap][2] ? av[ap]+2 : av[++ap] ; if ( (ofp=fopen(cp,"a")) == NULL ) { fprintf(stderr,"? Can't open for append file: '%s'\n",cp); return 1; } break; case 'b': case 'B': /* Open binary file for output */ cp = av[ap][2] ? av[ap]+2 : av[++ap] ; if ( (ofp=fopen(cp,WB)) == NULL ) { fprintf(stderr,"? Can't create file: '%s'\n",cp); return 1; } pfb = 1; break; case 'c': case 'C': /* Copy specified file to output as is */ /* Generally, this code solves problems of the file merging of different record type in VMS operating system. */ cp = av[ap][2] ? av[ap]+2 : av[++ap] ; if ( cp[0] == '-' && cp[1] == 0 ) ifp = stdin ; else if ( (ifp=fopen(cp,"r")) == NULL ) { fprintf(stderr,"? Can't found file: '%s'\n",cp); return 1; } while ( fgets(buf,sizeof(buf),ifp) != NULL ) fputs(buf,ofp); if ( ifp != stdin ) fclose(ifp); Files++; break; case 'u': case 'U': /* Open binary file for output */ uFileName = av[ap][2] ? av[ap]+2 : av[++ap] ; break; case 'n': case 'N': /* Load required names ... */ Need_Chars = av[ap] + 2 ; break; case 'i': case 'I': /* Install font search path */ FontSearchPath = av[ap]+2; break; case 'm': case 'M': /* font mapping file */ cp = av[ap][2] ? av[ap]+2 : av[++ap] ; if ( (fp=fopen(cp,"r")) == NULL ) {fprintf(stderr,"? SubFont: Can't found file '%s'\n",cp); return 1;} while ( fgets(buf,sizeof(buf),fp) != NULL ) { char *fontp,*ecp; for( cp = buf; *cp && *cp <= ' ' ; cp++ ); /* skip spaces */ if ( *cp == 0 || *cp == '%' ) continue; /* Comment or empty line */ if ( *cp == '/' ) { /* Process GhostScript like font map */ fontp = ++cp; while ( *cp && *cp > ' ' ) cp++; /* search end of font name */ *cp++ = 0; while ( *cp && *cp <= ' ' ) cp++; if ( *cp == '(' ) { /* Format like to: '/FontName (file-name) ; */ for( ecp = ++cp; *ecp && *ecp > ' ' && *ecp != ')'; ecp++); *ecp = 0; } else { /* Format like to: '/Fontmap file-name' */ for( ecp=cp ; *ecp && *ecp > ' ' ; ecp++); *ecp = 0; } } else { /* Process simple format Fontmap */ fontp = cp; while ( *cp && *cp > ' ' ) cp++; /* search end of font name */ *cp++ = 0; while ( *cp && *cp <= ' ' ) cp++; for( ecp=cp ; *ecp && *ecp > ' ' ; ecp++); *ecp = 0; } /* Add entry to font mapping list */ fmp = xmalloc(sizeof(struct FontMap)); fmp->next = fontMap; fmp->fontName = xstrdup(fontp); fmp->fileName = xstrdup(cp); fontMap = fmp; } fclose(fp); break; case 'f': case 'F': /* Load all fonts according psfontstat list */ if ( pfb ) { fprintf(stderr, "Processing several fonts into one PFB not available.\n"); return 1; } else { cp = av[ap][2] ? av[ap]+2 : (ap+1next) if ( strcmp(fmp->fontName,fontName) == 0 ) { /* fprintf(stderr,"Font '%s' looks in file '%s'\n", fmp->fontName,fmp->fileName); */ strcpy(fontName,fmp->fileName); break; } /* install list of required characters */ Need_Chars = cp; /* Search font file */ for( ifp = NULL, cp = FontSearchPath ; *cp > ' ' ; cp = ep ) { int j; if( (ep=strchr(cp,PATH_DELIMITER)) == NULL ) ep = cp + strlen(cp); j = (int)(ep - cp); if ( *ep == PATH_DELIMITER ) ep++; memcpy(fileName,cp,j); if ( FILE_DELIMITER != '\0' ) if ( j && fileName[j-1] != FILE_DELIMITER ) fileName[j++] = FILE_DELIMITER; strcpy(fileName+j,fontName); j = strlen(fileName); if ( Verbose ) fprintf(stderr,"Try open '%s'\n",fileName); if ( (ifp=fopen(fileName,RB)) != NULL ) break; if ( strcmp(fntName,fontName) == 0 ) { strcpy(fileName+j,".pfb"); if ( Verbose ) fprintf(stderr,"Try open '%s'\n",fileName); if ( (ifp=fopen(fileName,RB)) != NULL ) break; strcpy(fileName+j,".pfa"); if ( Verbose ) fprintf(stderr,"Try open '%s'\n",fileName); if ( (ifp=fopen(fileName,RB)) != NULL ) break; } } if ( ifp == NULL ) { fprintf(stderr,"Can't found font '%s' in path '%s'\n", fontName,FontSearchPath); if ( ufp == NULL && uFileName != NULL ) { if ( (ufp=fopen(uFileName,"w")) == NULL ) { fprintf(stderr,"? Can't create file: '%s'\n",uFileName); } } if ( ufp != NULL ) fprintf(ufp,"%s\n",fontName); continue; } else fprintf(stderr,"Process font '%s' from file '%s'\n", fntName,fileName); /*fprintf(ofp,"(Loading font %s\\n) print flush\n",fontName);*/ TouchEncoding++; Eexec_Output--; ifp = Set_Adequate_Read_Mode( ifp , fileName ); Process_Font( Need_Chars ); Eexec_Output++; TouchEncoding--; if ( ifp != stdin ) fclose(ifp); Files++; } } break; case 'z': case 'Z': /* This command is used to make font map */ if ( av[ap][2] == '\0' ) ofp = stdout; else if ( (ofp=fopen(av[ap]+2,"a")) == NULL ) { fprintf(stderr,"? SubFont: Can't write file '%s'\n",av[ap]+2); return 1; } for( ap++ ; ap < ac ; ap++ ) Scan_FontName( av[ap] , ofp ); return 0; default: fprintf(stderr,"? SubFont: Unknown option '%s'\n",av[ap]); return 1; } else { if ( pfb && Files ) { fprintf(stderr, "Processing several fonts into one PFB not available.\n"); return 1; } # ifndef vms if ( av[ap][0] == '-' && av[ap][1] == 0 ) ifp = stdin ; else # endif if ( (ifp=fopen(av[ap],RB)) == NULL ) { fprintf(stderr,"? Can't found file: '%s'\n",av[ap]); return 1; } ifp = Set_Adequate_Read_Mode( ifp , av[ap] ); if ( Need_Chars == NULL ) { if ( Copying_Full_Font() ) exit(1); } else Process_Font( Need_Chars ); if ( ifp != stdin ) fclose(ifp); Files++; } if ( ! Files ) { fprintf(stderr,"%s designed by %s\n",PROBLEM,AUTHOR); fprintf(stderr,"Shortly called %s, Version %s/%s, Revision Date %s\n", PROGRAM, VERSION, SYSID, REVDATE); fprintf(stderr,"Copyright (C) %s All Rights Reserved.\n\n",COPYRIGHT); fprintf(stderr,"Usage: SubFont [options] { -n... | } \n"); fprintf(stderr," Options are:\n"); fprintf(stderr," -v - Verbose ...\n"); fprintf(stderr," -o - Output file (Default is stdout)\n"); fprintf(stderr," -a - Output file in append(text) mode\n"); fprintf(stderr," -b - Output binary file (PFB)\n"); fprintf(stderr," -c - Copying specified file to output as is\n"); fprintf(stderr," -n/../../ - List of names of required characters ...\n"); fprintf(stderr," - Process font from file...\n"); # ifndef vms fprintf(stderr," - - Process font from stdin...\n"); # endif fprintf(stderr," -f - Process font list from file.\n"); fprintf(stderr," -m - Font mapping file (used with -f)\n"); fprintf(stderr," -I - Font search path (used with -f)\n"); fprintf(stderr," Default='%s'\n",FontSearchPath); fprintf(stderr," -u - File for put list of undefined fonts (used with -f)\n"); fprintf(stderr," -e# - Encoding optimization flag...\n"); fprintf(stderr," -x# - output eexec using flag...\n"); fprintf(stderr," -z - read files and print it PS name...\n"); return 1; } else { fprintf(stderr,"Totaly %d files are processed.\n",Files % 10000 ); if ( Verbose ) fprintf(stderr,"Totally %d unused bytes in Subr arrays\n",ArrLosts); } if ( ofp != stdout ) fclose(ofp); if ( ufp != NULL ) fclose(ufp); return 0; }