diff options
Diffstat (limited to 'Build/source/texk/dvipsk/finclude.c')
-rw-r--r-- | Build/source/texk/dvipsk/finclude.c | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/Build/source/texk/dvipsk/finclude.c b/Build/source/texk/dvipsk/finclude.c new file mode 100644 index 00000000000..1f38aec0f1c --- /dev/null +++ b/Build/source/texk/dvipsk/finclude.c @@ -0,0 +1,516 @@ +/* + * Code for allowing fonts to be used in PostScript files given via + * `psfile=...'. + * + * Modified to check for font usage (DocumentFonts and DocumentNeededResources) + * in all included postscript files. This information is added to the + * global list of postscript fonts used (ps_fonts_used). Each font is + * also looked up (from psfonts.map) and if a file needs to be downloaded + * for that font, it is added (with add_header). + * 11/1996 Aaron Sawdey + */ +#include "dvips.h" /* The copyright notice in that file is included too! */ +#ifdef KPATHSEA +#include <kpathsea/c-ctype.h> +#else +#include <ctype.h> +#if !defined(SYSV) && !defined(WIN32) +extern char *strtok(); /* some systems don't have this in strings.h */ +#endif +#define ISXGIGIT isxdigit +#endif +#ifdef VMS +#define getname vms_getname +#endif + +#ifndef STDC_HEADERS +double atof(); +#endif + +/* + * The external declarations: + */ +#include "protos.h" + +/* + * Create a font descriptor for a font included in a psfile. There will be + * no fontmaptype node for the resulting font descriptor until this font is + * encountered by fontdef() (if that ever happens). + */ +static fontdesctype * +ifontdef(char *name, char *area, + int scsize, int dssize, char *scname) +{ + fontdesctype *fp; + + fp = newfontdesc((integer)0, scsize, dssize, name, area); + fp->scalename = scname; + fp->next = fonthead; + fonthead = fp; + return fp; +} +/* + * When a font appears in an included psfile for the first time, this routine + * links it into the fonthd[] array. + */ +static void +setfamily(fontdesctype *f) +{ + int i; + + fontmem -= DICTITEMCOST; + for (i=0; i<nextfonthd; i++) + if (strcmp(f->name, fonthd[i]->name)==0 + && strcmp(f->area, fonthd[i]->area)==0) { + f->nextsize = fonthd[i]; + fonthd[i] = f; + return; + } + if (nextfonthd==MAXFONTHD) + error("! Too many fonts in included psfiles"); + fontmem -= NAMECOST + strlen(f->name) + strlen(f->area); + fonthd[nextfonthd++] = f; + f->nextsize = NULL; +} +/* + * Convert file name s to a pair of new strings in the string pool. + * The first string is the original value of nextstring; the second + * string is the return value. + */ +static char* +getname(char *s) +{ + char *a, *p, sav; + + a = NULL; + for (p=s; *p!=0; p++) + if (*p=='/') + a = p+1; + if (a==NULL) *nextstring++ = 0; + else { sav = *a; + *a = 0; + (void) newstring(s); + *a = sav; + s = a; + } + return newstring(s); +} +/* + * Mark character usage in *f based on the hexadecimal bitmap found in + * string s. A two-digit offset separated by a colon gives the initial + * character code. We have no way of knowing how many times each character + * is used or how many strings get created when showing the characters so + * we just estimate two usages per character and one string per pair of + * usages. + */ +static void +includechars(fontdesctype *f, char *s) +{ + int b, c, d; + int l = strlen(s); + + while (l > 0 && (s[l-1] == '\n' || s[l-1] == '\r')) + s[--l] = 0; + if (!ISXDIGIT(s[0]) || !ISXDIGIT(s[1]) || s[2]!=':' + || strspn(s+3,"0123456789ABCDEFabcdef") < l-3) { + fprintf_str(stderr, "%s\n", s); + error("Bad syntax in included font usage table"); + return; + } + c = (xdig[(int)(s[0])] << 4) + xdig[(int)(s[1])]; + s += 2; + while (*++s) { + d = xdig[(int)*s]; + for (b=8; b!=0; b>>=1) { + if ((d&b)!=0) { + pagecost ++; + (void) prescanchar(&f->chardesc[c]); + } + if (++c==256) return; + } + } +} +/* + * String p should be start after the ":" in a font declaration of the form +%*FONT: <tfm-name> <scaled-size> <design-size> <2-hex-digits>:<hex-string> + * where the sizes are floating-point numbers in units of PostScript points + * (TeX's "bp"). We update the data structures for the included font, + * charge fontmem for the VM used, and add to delchar if necessary. + * Note that the scaled size and the design size are multiplied by mag/1000. + * This is needed for the design size to undo the similar factor in conv since + * design sizes are not supposed to be affected by magnification. Applying + * the magnification factor to the scaled size selects magnified fonts as is + * appropriate in the normal case where the included PostScript is scaled by + * mag/1000. The definition of `fshow' in finclude.lpro unscales by `DVImag' + * to account for this. We cannot change the font scaled size to account for + * options like `hscale=' because then the definition of `fshow' would have + * to change. + */ +static void +scan1fontcomment(char *p) +{ + char *q, *name, *area; + char *scname; /* location in buffer where we got scsize */ + integer scsize, dssize; + fontdesctype *fptr; + real DVIperBP; + + DVIperBP = actualdpi/(72.0*conv) * (mag/1000.0); + p = strtok(p, " "); + if (p==NULL) return; + area = nextstring; /* tentatively in the string pool */ + name = getname(p); + q = strtok((char *)0, " "); + if (p==NULL || (scsize=(integer)(atof(q)*DVIperBP))==0) { + fprintf_str(stderr, "%s\n",p); + error("No scaled size for included font"); + nextstring = area; /* remove from string pool */ + return; + } + scname = q; + q = strtok((char *)0, " "); + if (p==NULL || (dssize=(integer)(atof(q)*DVIperBP))==0) { + fprintf_str(stderr, "%s\n",p); + error("No design size for included font"); + nextstring = area; + return; + } + q = strtok((char *)0, " "); + fptr = matchfont(name, area, scsize, scname); + if (!fptr) { + fptr = ifontdef(name, area, scsize, dssize, newstring(scname)); + (void) preselectfont(fptr); + setfamily(fptr); + } else { + nextstring = area; /* remove from string pool */ + (void) preselectfont(fptr); + if (fptr->scalename==NULL) { + fptr->scalename=newstring(scname); + setfamily(fptr); + } + } + includesfonts = 1; + fptr->psflag |= THISPAGE; + includechars(fptr, q); +} +/* + * Parse the arguments to a "%%VMusage" comment. The Adobe Type 1 Font Format + * book specifies two arguments. This routine will accept one or two arguments; + * if there are two arguments we take the maximum. + */ +static integer +scanvm(char *p) +{ + char* q; + integer vm, vmmax; + + q = strtok(p, " "); + if (q==NULL) { + error("Missing data in VMusage comment"); + return 0; + } + vmmax = atol(q); + q = strtok((char *)0, " "); + if (q!=NULL && (vm=atol(q))>vmmax) + vmmax = vm; + return vmmax; +} +/* + * Scan a list of font names. + * Each name is added to the list ps_fonts_used, and if it has + * an associated header file (from psfonts.map), the header file + * is added with add_header. + */ +static void +scan_fontnames(char *str, const char *psfile) +{ + char *p,*pe; + struct resfont *re; + + /* Turn all newlines, CRs, and tabs into spaces. */ + p = str; + while(*p) { + if(*p == '\r' || *p == '\n' || *p == '\t') *p = ' '; + p++; + } + /* Remove trailing spaces. */ + p = str+strlen(str)-1; + while(p > str && *p == ' ') { + *p = '\0'; + p--; + } + + p = str; + while(*p == ' ') p++; /* skip leading whitespace */ + + while(p && *p) { + pe = strchr(p,' '); + if(pe != NULL) *pe = '\0'; + + add_name(p,&ps_fonts_used); + + if (1) { +#ifdef DEBUG + if (dd(D_FONTS)) + fprintf_str(stderr, + "Adding font '%s' from included postscript file '%s'.\n", + p,psfile); +#endif /* DEBUG */ + + re = findPSname(p); + if(re != NULL) { + if (re->sent != 2) { + if (re->Fontfile) { + add_header(re->Fontfile); + } else if (re->downloadheader) { + /* this code borrowed from residentfont() in resident.c */ + char *cp = re->downloadheader; + char *q; + + infont = re->PSname; + while (1) { + q = cp; + while (*cp && *cp != ' ') + cp++; + if (*cp) { + *cp = 0; + add_header(q); + *cp++ = ' '; + } else { + add_header(q); + break; + } + infont = 0; + } + } + infont = 0; + } + re->sent = 2; + if (unused_top_of_psnames < DOWNLOADEDPSSIZE) { + downloadedpsnames[unused_top_of_psnames] = xstrdup (re->PSname); + unused_top_of_psnames++; + } + } else { + char eb[1000]; + snprintf(eb, sizeof(eb), + "Font %s used in file %s is not in the mapping file.", + p, psfile); + error(eb); + } + } + + p = pe; + if(p != NULL) { + p++; + while(*p == ' ') p++; /* skip leading whitespace */ + } + } + + return; +} + +/* + * fc_state == 0: normal state, looking for interesting comments + * fc_state == 1: looking for %%+ following %%DocumentFonts + * fc_state == 2: looking for "%%+ font" following %%DocumentNeededResources + */ +static int fc_state = 0; +/* + * Do we need to check for information at the end of the postscript file? + */ +static int check_atend = 0; + +static void +scanfontusage(char *p, const char *psfile) +{ + if (strncmp(p, "%%DocumentFonts: ",17) == 0) { + p += 17; + while (*p && *p <= ' ') + p++; + if(!strncmp(p,"(atend)",7)) { + check_atend = 1; + } else { + scan_fontnames(p,psfile); + fc_state = 1; + } + } else if (strncmp(p, "%%DocumentNeededFonts: ",23)==0) { + p += 23; + while (*p && *p <= ' ') + p++; + if(!strncmp(p,"(atend)",7)) { + check_atend = 1; + } else { + scan_fontnames(p,psfile); + fc_state = 1; + } + } else if (fc_state == 1 && strncmp(p,"%%+",3) == 0) { + scan_fontnames(p+3,psfile); + fc_state = 1; + } else if (strncmp(p, "%%DocumentNeededResources: ",27) == 0) { + p += 27; + while (*p && *p <= ' ') + p++; + if(!strncmp(p,"(atend)",7)) { + check_atend = 1; + } else { + if(!strncmp(p,"font ",5)) scan_fontnames(p+5,psfile); + fc_state = 2; + } + } else if (fc_state == 2 && strncmp(p,"%%+",3) == 0) { + p += 3; + while (*p && *p <= ' ') + p++; + if(!strncmp(p,"font ",5)) scan_fontnames(p+5,psfile); + fc_state = 2; + } else { + fc_state = 0; + } + return; +} + +/* + * Scan an initial sequence of comment lines looking for font and memory + * usage specifications. This does not handle the "atend" construction. + */ +void +scanfontcomments(const char *filename) +{ + char p[500]; + char *r; + FILE *f; + integer truecost = pagecost; + Boolean trueknown = 0; + fontdesctype *oldcf = curfnt; + +#ifdef DEBUG + if (dd(D_FONTS)) + fprintf_str(stderr, + "Checking for fonts in '%s'\n",filename); +#endif /* DEBUG */ + + if (*filename == '`') { +/* + * Allow scanning of ` commands. Better return same results both times. + */ + f = popen(filename+1, "r"); + SET_BINARY(fileno(f)); + to_close = USE_PCLOSE; + } else { + f = search(figpath, filename, READ); + } + if (f) { + SET_BINARY(fileno(f)); + fc_state = 0; + check_atend = 0; + while (fgets(p,500,f) && p[0]=='%' && + (p[1]=='!' || p[1]=='%' || p[1]=='*')) { + if (strncmp(p, "%*Font:", 7) == 0) { + scan1fontcomment(p+7); + } else if (strncmp(p, "%%VMusage:", 9) == 0) { + truecost += scanvm(p+10); + trueknown = 1; + } + scanfontusage(p,filename); + } + if (trueknown) + pagecost = truecost; + + if(check_atend) { +#ifdef DEBUG + if (dd(D_FONTS)) + fprintf_str(stderr, + "Checking for (atend) fonts in '%s'\n",filename); +#endif /* DEBUG */ + + fc_state = 0; + + fseek(f,-4096,2); /* seek to 4096 bytes before EOF. */ + fgets(p,500,f); /* throw away a partial line. */ + + /* find %%Trailer */ + while((r=fgets(p,500,f)) && strncmp(p,"%%Trailer",9)); + + /* look for specs that were deferred to the trailer. */ + if(r != NULL) { + while(fgets(p,500,f)) { + if(p[0]=='%' && p[1]=='%') scanfontusage(p,filename); + } + } +#ifdef DEBUG + else { /* r == NULL */ + if (dd(D_FONTS)) + fprintf_str(stderr, + "Did not find %%%%Trailer in included file '%s'.\n", + filename); + } +#endif /* DEBUG */ + } + close_file(f); + } + curfnt = oldcf; +} +/* + * Is string s less than 30 characters long with no special characters + * that are not allowed in PostScript commands. + */ +static Boolean +okascmd(char *ss) +{ + register int c = 0; + register char *s = ss; + + while (*s) + if (*s<' ' || *s>126 || ++c==30) + return(0); + return(strcspn(ss,"()<>[]{}%/") == c); +} +/* + * Output font area and font name strings as a literal string + */ +static void +nameout(char *area, char *name) +{ + char buf[500]; + char *s; + + if (*area==0 && okascmd(name)) { + snprintf(buf, sizeof(buf), "/%s", name); + cmdout(name); + } else { + for (s=area; *s; s++) + scout(*s); + for (s=name; *s; s++) + scout(*s); + stringend(); + cmdout("cvn"); + } +} +/* + * Output commands for defining a table of PostScript font identifiers for + * fonts used in included psfiles in the current section. + */ +void +fonttableout(void) +{ + int i, k; + fontdesctype *f; + + for (i=0; i<nextfonthd; i++) { + for (f=fonthd[i]; f!=NULL; f=f->nextsize) + if (f->psflag==EXISTS) break; + if (f!=NULL) { + nameout(f->area, f->name); + k = 0; + do { + if (f->psflag==EXISTS) { + cmdout(f->scalename); + lfontout((int)f->psname); + k++; + } + f = f->nextsize; + } while (f!=NULL); + numout((integer)k); + cmdout("fstore"); + } + } +} |