Back to index

tetex-bin  3.0
finclude.c
Go to the documentation of this file.
00001 /*
00002  *  Code for allowing fonts to be used in PostScript files given via
00003  *  `psfile=...'.
00004  *
00005  * Modified to check for font usage (DocumentFonts and DocumentNeededResources)
00006  * in all included postscript files. This information is added to the
00007  * global list of postscript fonts used (ps_fonts_used). Each font is
00008  * also looked up (from psfonts.map) and if a file needs to be downloaded
00009  * for that font, it is added (with add_header).
00010  * 11/1996 Aaron Sawdey
00011  */
00012 #include "dvips.h" /* The copyright notice in that file is included too! */
00013 #ifdef KPATHSEA
00014 #include <kpathsea/c-ctype.h>
00015 #else
00016 #include <ctype.h>
00017 #if !defined(SYSV) && !defined(WIN32)
00018 extern char *strtok() ; /* some systems don't have this in strings.h */
00019 #endif
00020 #define ISXGIGIT isxdigit
00021 #endif
00022 #ifdef VMS
00023 #define getname vms_getname
00024 #endif
00025 
00026 #ifndef STDC_HEADERS
00027 double atof();
00028 #endif
00029 
00030 /*
00031  *   These are the external routines we call.
00032  */
00033 #include "protos.h"
00034 
00035 /*
00036  *   These are the external variables we access.
00037  */
00038 extern struct header_list *ps_fonts_used;
00039 extern char *infont ;
00040 extern fontdesctype *curfnt ;
00041 extern fontdesctype *fonthead ;
00042 extern integer fontmem ;
00043 extern fontdesctype *fonthd[MAXFONTHD] ;
00044 extern int nextfonthd ;
00045 extern char *nextstring ;
00046 extern char xdig[256] ;
00047 extern real conv ;
00048 extern integer pagecost ;
00049 extern int actualdpi ;
00050 extern double mag ;
00051 extern Boolean includesfonts ;
00052 #ifndef KPATHSEA
00053 extern char *figpath ;
00054 #endif
00055 extern int to_close ;
00056 #ifdef DEBUG
00057 extern integer debug_flag;
00058 #endif  /* DEBUG */
00059 
00060 /*
00061  * Create a font descriptor for a font included in a psfile.  There will be
00062  * no fontmaptype node for the resulting font descriptor until this font is
00063  * encountered by fontdef() (if that ever happens).
00064  */
00065 fontdesctype *
00066 ifontdef P5C(char *, name, char *, area, 
00067             int, scsize, int, dssize, char *, scname)
00068 {
00069    fontdesctype *fp;
00070 
00071    fp = newfontdesc((integer)0, scsize, dssize, name, area);
00072    fp->scalename = scname;
00073    fp->next = fonthead ;
00074    fonthead = fp ;
00075    return fp;
00076 }
00077 /*
00078  * When a font appears in an included psfile for the first time, this routine
00079  * links it into the fonthd[] array.
00080  */
00081 void
00082 setfamily P1C(fontdesctype *, f)
00083 {
00084    int i ;
00085 
00086    fontmem -= DICTITEMCOST;
00087    for (i=0; i<nextfonthd; i++)
00088       if (strcmp(f->name, fonthd[i]->name)==0
00089             && strcmp(f->area, fonthd[i]->area)==0) {
00090          f->nextsize = fonthd[i];
00091          fonthd[i] = f;
00092          return;
00093       }
00094    if (nextfonthd==MAXFONTHD)
00095       error("! Too many fonts in included psfiles") ;
00096    fontmem -= NAMECOST + strlen(f->name) + strlen(f->area) ;
00097    fonthd[nextfonthd++] = f ;
00098    f->nextsize = NULL ;
00099 }
00100 /*
00101  * Convert file name s to a pair of new strings in the string pool.
00102  * The first string is the original value of nextstring; the second
00103  * string is the return value.
00104  */
00105 char*
00106 getname P1C(char *, s)
00107 {
00108    char *a, *p, sav;
00109 
00110    a = NULL;
00111    for (p=s; *p!=0; p++)
00112       if (*p=='/')
00113          a = p+1 ;
00114    if (a==NULL) *nextstring++ = 0 ;
00115    else {   sav = *a ;
00116       *a = 0 ;
00117       (void) newstring(s) ;
00118       *a = sav ;
00119       s = a ;
00120    }
00121    return newstring(s);
00122 }
00123 /*
00124  * Mark character usage in *f based on the hexadecimal bitmap found in
00125  * string s.  A two-digit offset separated by a colon gives the initial
00126  * character code.  We have no way of knowing how many times each character
00127  * is used or how many strings get created when showing the characters so
00128  * we just estimate two usages per character and one string per pair of
00129  * usages.
00130  */
00131 void
00132 includechars P2C(fontdesctype *, f, char *, s)
00133 {
00134    int b, c, d ;
00135    int l = strlen(s) ;
00136 
00137    while (l > 0 && (s[l-1] == '\n' || s[l-1] == '\r'))
00138       s[--l] = 0 ;
00139    if (!ISXDIGIT(s[0]) || !ISXDIGIT(s[1]) || s[2]!=':'
00140          || strspn(s+3,"0123456789ABCDEFabcdef") < l-3) {
00141       fprintf(stderr, "%s\n", s) ;
00142       error("Bad syntax in included font usage table") ;
00143       return ;
00144    }
00145    c = (xdig[(int)(s[0])] << 4) + xdig[(int)(s[1])] ;
00146    s += 2 ;
00147    while (*++s) {
00148       d = xdig[(int)*s] ;
00149       for (b=8; b!=0; b>>=1) {
00150          if ((d&b)!=0) {
00151             pagecost ++ ;
00152             (void) prescanchar(&f->chardesc[c]) ;
00153          }
00154          if (++c==256) return ;
00155       }
00156    }
00157 }
00158 /*
00159  * String p should be start after the ":" in a font declaration of the form
00160 %*FONT: <tfm-name> <scaled-size> <design-size> <2-hex-digits>:<hex-string>
00161  * where the sizes are floating-point numbers in units of PostScript points
00162  * (TeX's "bp").  We update the data structures for the included font,
00163  * charge fontmem for the VM used, and add to delchar if necessary.
00164  * Note that the scaled size and the design size are multiplied by mag/1000.
00165  * This is needed for the design size to undo the similar factor in conv since
00166  * design sizes are not supposed to be affected by magnification.  Applying
00167  * the magnification factor to the scaled size selects magnified fonts as is
00168  * appropriate in the normal case where the included PostScript is scaled by
00169  * mag/1000.  The definition of `fshow' in finclude.lpro unscales by `DVImag'
00170  * to account for this.  We cannot change the font scaled size to account for
00171  * options like `hscale=' because then the definition of `fshow' would have
00172  * to change.
00173  */
00174 void
00175 scan1fontcomment P1C(char *, p)
00176 {
00177    char *q, *name, *area;
00178    char *scname;      /* location in buffer where we got scsize */
00179    integer scsize, dssize;
00180    fontdesctype *fptr;
00181    real DVIperBP;
00182 
00183    DVIperBP = actualdpi/(72.0*conv) * (mag/1000.0);
00184    p = strtok(p, " ");
00185    if (p==NULL) return;
00186    area = nextstring ;   /* tentatively in the string pool */
00187    name = getname(p);
00188    q = strtok((char *)0, " ");
00189    if (p==NULL || (scsize=(integer)(atof(q)*DVIperBP))==0) {
00190       fprintf(stderr, "%s\n",p);
00191       error("No scaled size for included font");
00192       nextstring = area ;   /* remove from string pool */
00193       return;
00194    }
00195    scname = q;
00196    q = strtok((char *)0, " ");
00197    if (p==NULL || (dssize=(integer)(atof(q)*DVIperBP))==0) {
00198       fprintf(stderr, "%s\n",p);
00199       error("No design size for included font");
00200       nextstring = area ;
00201       return;
00202    }
00203    q = strtok((char *)0, " ");
00204    fptr = matchfont(name, area, scsize, scname);
00205    if (!fptr) {
00206       fptr = ifontdef(name, area, scsize, dssize, newstring(scname));
00207       (void) preselectfont(fptr);
00208       setfamily(fptr);
00209    } else {
00210       nextstring = area;   /* remove from string pool */
00211       (void) preselectfont(fptr);
00212       if (fptr->scalename==NULL) {
00213          fptr->scalename=newstring(scname);
00214          setfamily(fptr);
00215       }
00216    }
00217    includesfonts = 1;
00218    fptr->psflag |= THISPAGE;
00219    includechars(fptr, q);
00220 }
00221 /*
00222  * Parse the arguments to a "%%VMusage" comment.  The Adobe Type 1 Font Format
00223  * book specifies two arguments. This routine will accept one or two arguments;
00224  * if there are two arguments we take the maximum.
00225  */
00226 integer
00227 scanvm P1C(char *, p)
00228 {
00229    char* q;
00230    integer vm, vmmax;
00231 
00232    q = strtok(p, " ");
00233    if (q==NULL) {
00234       error("Missing data in VMusage comment");
00235       return 0;
00236    }
00237    vmmax = atol(q);
00238    q = strtok((char *)0, " ");
00239    if (q!=NULL && (vm=atol(q))>vmmax)
00240       vmmax = vm;
00241    return vmmax;
00242 }
00243 /*
00244  * Scan a list of font names.
00245  * Each name is added to the list ps_fonts_used, and if it has
00246  * an associated header file (from psfonts.map), the header file
00247  * is added with add_header.
00248  */
00249 void
00250 scan_fontnames P2C(char *, str, char *, psfile)
00251 {
00252   char *p,*pe;
00253   struct resfont *re;
00254   int i;
00255 
00256   /* Turn all newlines, CRs, and tabs into spaces. */
00257   p = str;
00258   while(*p) {
00259     if(*p == '\r' || *p == '\n' || *p == '\t') *p = ' ';
00260     p++;
00261   }
00262   /* Remove trailing spaces. */
00263   p = str+strlen(str)-1;
00264   while(p > str && *p == ' ') {
00265     *p = '\0';
00266     p--;
00267   }
00268 
00269   p = str;
00270   while(*p == ' ') p++; /* skip leading whitespace */
00271 
00272   while(p && *p) {
00273      pe = strchr(p,' ');
00274      if(pe != NULL) *pe = '\0';
00275 
00276      i = add_name(p,&ps_fonts_used);
00277 
00278      if (1) {
00279 #ifdef DEBUG
00280        if (dd(D_FONTS))
00281          (void)fprintf(stderr,
00282                      "Adding font '%s' from included postscript file '%s'.\n",
00283                      p,psfile);
00284 #endif  /* DEBUG */
00285 
00286        re = findPSname(p);
00287        if(re != NULL) {
00288          if (re->sent != 2) {
00289             if (re->Fontfile) {
00290                add_header(re->Fontfile) ;
00291             } else if (re->downloadheader) {
00292        /* this code borrowed from residentfont() in resident.c */
00293              char *cp = re->downloadheader ;
00294              char *q ;
00295         
00296              infont = re->PSname ;
00297              while (1) {
00298                q = cp ;
00299                while (*cp && *cp != ' ')
00300                   cp++ ;
00301                if (*cp) {
00302                   *cp = 0 ;
00303                   add_header(q) ;
00304                   *cp++ = ' ' ;
00305                } else {
00306                   add_header(q) ;
00307                   break ;
00308                }
00309                infont = 0 ;
00310              }
00311             }
00312            infont = 0 ;
00313           }
00314           re->sent = 2 ;
00315         } else {
00316           char eb[1000];
00317           sprintf(eb,"Font %s used in file %s is not in the mapping file.",
00318                   p,psfile);
00319           error(eb);
00320         }
00321      }
00322 
00323      p = pe;
00324      if(p != NULL) {
00325        p++;
00326        while(*p == ' ') p++; /* skip leading whitespace */
00327      }
00328   }
00329 
00330   return;
00331 }
00332 
00333 /*
00334  * fc_state == 0: normal state, looking for interesting comments
00335  * fc_state == 1: looking for %%+ following %%DocumentFonts
00336  * fc_state == 2: looking for "%%+ font" following %%DocumentNeededResources
00337  */
00338 static int fc_state = 0;
00339 /*
00340  * Do we need to check for information at the end of the postscript file? 
00341  */
00342 static int check_atend = 0;
00343 
00344 void
00345 scanfontusage P2C(char *, p, char *, psfile)
00346 {
00347   if (strncmp(p, "%%DocumentFonts: ",17) == 0) {
00348     p += 17 ;
00349     while (*p && *p <= ' ')
00350        p++ ;
00351     if(!strncmp(p,"(atend)",7)) {
00352       check_atend = 1;
00353     } else {
00354       scan_fontnames(p,psfile);
00355       fc_state = 1;
00356     }
00357   } else if (strncmp(p, "%%DocumentNeededFonts: ",23)==0) {
00358     p += 23 ;
00359     while (*p && *p <= ' ')
00360        p++ ;
00361     if(!strncmp(p,"(atend)",7)) {
00362       check_atend = 1;
00363     } else {
00364       scan_fontnames(p,psfile);
00365       fc_state = 1;
00366     }
00367   } else if (fc_state == 1 && strncmp(p,"%%+",3) == 0) {
00368     scan_fontnames(p+3,psfile);
00369     fc_state = 1;
00370   } else if (strncmp(p, "%%DocumentNeededResources: ",27) == 0) {
00371     p += 27 ;
00372     while (*p && *p <= ' ')
00373        p++ ;
00374     if(!strncmp(p,"(atend)",7)) {
00375       check_atend = 1;
00376     } else {
00377       if(!strncmp(p,"font ",5)) scan_fontnames(p+5,psfile);
00378       fc_state = 2;
00379     }
00380   } else if (fc_state == 2 && strncmp(p,"%%+",3) == 0) {
00381     p += 3 ;
00382     while (*p && *p <= ' ')
00383        p++ ;
00384     if(!strncmp(p,"font ",5)) scan_fontnames(p+5,psfile);
00385     fc_state = 2;
00386   } else {
00387     fc_state = 0;
00388   }
00389   return;
00390 }
00391 
00392 /*
00393  * Scan an initial sequence of comment lines looking for font and memory
00394  * usage specifications.  This does not handle the "atend" construction.
00395  */
00396 void
00397 scanfontcomments P1C(char *, filename)
00398 {
00399    char p[500];
00400    char *r;
00401    FILE *f;
00402    integer truecost = pagecost ;
00403    Boolean trueknown = 0 ;
00404    fontdesctype *oldcf = curfnt;
00405 
00406 #ifdef DEBUG
00407       if (dd(D_FONTS))
00408          (void)fprintf(stderr,
00409                      "Checking for fonts in '%s'\n",filename);
00410 #endif  /* DEBUG */
00411 
00412    if (*filename == '`') {
00413 /*
00414  *   Allow scanning of ` commands.  Better return same results both times.
00415  */
00416       f = popen(filename+1, "r") ;
00417       to_close = USE_PCLOSE ;
00418    } else {
00419       f = search(figpath, filename, READ) ;
00420    }
00421    if (f) {
00422      SET_BINARY(fileno(f)) ;
00423      fc_state = 0;
00424      check_atend = 0;
00425      while (fgets(p,500,f) && p[0]=='%' &&
00426             (p[1]=='!' || p[1]=='%' || p[1]=='*')) {
00427        if (strncmp(p, "%*Font:", 7) == 0) {
00428         scan1fontcomment(p+7);
00429        } else if (strncmp(p, "%%VMusage:", 9) == 0) {
00430         truecost += scanvm(p+10) ;
00431         trueknown = 1 ;
00432        }
00433        scanfontusage(p,filename);
00434      }
00435      if (trueknown)
00436        pagecost = truecost ;
00437 
00438      if(check_atend) {
00439 #ifdef DEBUG
00440        if (dd(D_FONTS))
00441          (void)fprintf(stderr,
00442                      "Checking for (atend) fonts in '%s'\n",filename);
00443 #endif  /* DEBUG */
00444 
00445        fc_state = 0;
00446        
00447        fseek(f,-4096,2); /* seek to 4096 bytes before EOF. */
00448        fgets(p,500,f); /* throw away a partial line. */
00449 
00450        /* find %%Trailer */
00451        while((r=fgets(p,500,f)) && strncmp(p,"%%Trailer",9)) ;
00452 
00453        /* look for specs that were deferred to the trailer. */
00454        if(r != NULL) {
00455         while(fgets(p,500,f)) {
00456           if(p[0]=='%' && p[1]=='%') scanfontusage(p,filename);
00457         }
00458        }
00459 #ifdef DEBUG
00460        else { /* r == NULL */
00461         if (dd(D_FONTS))
00462          (void)fprintf(stderr,
00463                      "Did not find %%%%Trailer in included file '%s'.\n",
00464                      filename);
00465        }
00466 #endif  /* DEBUG */
00467      }
00468      close_file(f) ;
00469    }
00470    curfnt = oldcf;
00471 }
00472 /*
00473  * Is string s less than 30 characters long with no special characters
00474  * that are not allowed in PostScript commands.
00475  */
00476 Boolean
00477 okascmd P1C(char *, ss)
00478 {
00479    register int c = 0 ;
00480    register char *s = ss ;
00481 
00482    while (*s)
00483       if (*s<' ' || *s>126 || ++c==30)
00484          return(0) ;
00485    return(strcspn(ss,"()<>[]{}%/") == c) ;
00486 }
00487 /*
00488  * Output font area and font name strings as a literal string
00489  */
00490 void
00491 nameout P2C(char *, area, char *, name)
00492 {
00493    char buf[30] ;
00494    char *s ;
00495 
00496    if (*area==0 && okascmd(name)) {
00497       (void)sprintf(buf, "/%s", name) ;
00498       cmdout(name);
00499    } else {
00500       for (s=area; *s; s++)
00501          scout(*s) ;
00502       for (s=name; *s; s++)
00503          scout(*s) ;
00504       stringend();
00505       cmdout("cvn") ;
00506    }
00507 }
00508 /*
00509  * Output commands for defining a table of PostScript font identifiers for
00510  * fonts used in included psfiles in the current section.
00511  */
00512 void
00513 fonttableout P1H(void)
00514 {
00515    int i, k;
00516    fontdesctype *f;
00517 
00518    for (i=0; i<nextfonthd; i++) {
00519       for (f=fonthd[i]; f!=NULL; f=f->nextsize)
00520          if (f->psflag==EXISTS) break;
00521       if (f!=NULL) {
00522          nameout(f->area, f->name);
00523          k = 0;
00524          do {
00525             if (f->psflag==EXISTS) {
00526                cmdout(f->scalename);
00527                lfontout((int)f->psname);
00528                k++;
00529             }
00530             f = f->nextsize;
00531          } while (f!=NULL);
00532          numout((integer)k);
00533          cmdout("fstore");
00534       }
00535    }
00536 }