/* * Copyright (c) 1984, 1985, 1986 Xerox Corp. * * Handle troff metrics here. * * note that Troff uses "fat points" of which there are exactly 72 per inch. * * HISTORY * 15-Apr-86 Lee Moore (lee) at Xerox Webster Research Center * Now prints out the number of special character names in the * DESC file. * * Nov, 1985 Lee Moore, Xerox Webster Research Center * Created. */ #include <stdio.h> #include <math.h> #include "stack.h" #include "token.h" #include "config.h" #include "ipmetrics.h" #include "troff.h" #include "strings.h" #define TRUE 1 #define FALSE 0 /* the following value should be choosen so that none of the widths * is greater than 256 */ #define UNITWIDTH 5 /* was 10 */ #define MAXSPECIALNAMES 221 /* maximum number of special characters. * this constant is fixed in Troff */ #define public #define private static public char *malloc(); public char *DeviceName, *LibraryDirectory; struct CharElement { struct CharElement *Next; char CharName[3]; }; private struct CharElement *CharSet = NULL; private int SetOfPointSizes[MAXPOINTSIZE], FontCount = 0; /* * Clean up our state */ public CleanUpTroff(configChain) struct FontConfig *configChain; { struct FontConfig *p; WriteDescFile(configChain); WriteFontMapFile(configChain); WriteInstallFile(configChain); WriteCleanUpFile(configChain); /* if we haven't seen a font, say so! */ for( p = configChain; p != NULL; p = p->Next ) if( !p->SeenFlag ) printf("couldn't find: %s/%s/%s\n", p->FontPt1, p->FontPt2, p->FontPt3); } /* * Write the DESC file */ private WriteDescFile(configChain) struct FontConfig *configChain; { int i; FILE *deviceFile; struct FontConfig *p; if( (deviceFile = fopen("DESC", "w")) == NULL ) { printf("can't open 'DESC' for writing\n"); exit(1); } /* output boiler plate */ fprintf(deviceFile, "# describe the '%s' interpress device\n", DeviceName); fprintf(deviceFile, "res %d\n", MICAS_PER_INCH); fprintf(deviceFile, "hor 1\n"); fprintf(deviceFile, "vert 1\n"); fprintf(deviceFile, "unitwidth %d\n", UNITWIDTH); fprintf(deviceFile, "paperwidth %d\n", PAGE_WIDTH_IN_MICAS); fprintf(deviceFile, "paperlength %d\n", PAGE_HEIGHT_IN_MICAS); /* output sizes */ fprintf(deviceFile, "sizes "); for( i = 1; i < MAXPOINTSIZE; i++ ) if( SetOfPointSizes[i] ) fprintf(deviceFile," %d", i); fprintf(deviceFile, " 0\n"); /* output fonts */ fprintf(deviceFile, "fonts %d ", FontCount); for( p = configChain; p != NULL; p = p->Next ) if( p->SeenFlag ) fprintf(deviceFile, "%s ", p->TargetName); fprintf(deviceFile, "\n"); PrintCharSet(deviceFile); (void) fclose(deviceFile); } /* * Write the file that shows the relationship between Troff names and * Interpress names */ private WriteFontMapFile(configChain) struct FontConfig *configChain; { FILE *fontMapFile; struct FontConfig *p; if( (fontMapFile = fopen(FONTMAPFILENAME, "w")) == NULL ) { fprintf(stderr, "can't open the file '%s' for writing\n", FONTMAPFILENAME); return; } for( p = configChain; p != NULL; p = p->Next ) if( p->SeenFlag ) fprintf(fontMapFile, "%s %s/%s/%s\n", p->TargetName, p->FontPt1, p->FontPt2, p->FontPt3); (void) fclose(fontMapFile); (void) chmod(FONTMAPFILENAME, 0755); } /* * Create a shell script that will install all these things */ private WriteInstallFile(configChain) struct FontConfig *configChain; { FILE *installFile; struct FontConfig *p; if( (installFile = fopen(INSTALLNAME, "w")) == NULL ) { fprintf(stderr, "can't open the file 'install' for writing\n"); return; } fprintf(installFile, "#! /bin/sh\n"); fprintf(installFile, "if test ! -d %s/fonts/%s\n", LibraryDirectory, DeviceName); fprintf(installFile, " then\n"); fprintf(installFile, " mkdir %s/fonts/%s\n", LibraryDirectory, DeviceName); fprintf(installFile, " fi\n"); fprintf(installFile, "if test ! -d %s/fonts/%s/devipress\n", LibraryDirectory, DeviceName); fprintf(installFile, " then\n"); fprintf(installFile, " mkdir %s/fonts/%s/devipress\n", LibraryDirectory, DeviceName); fprintf(installFile, " fi\n"); for( p = configChain; p != NULL; p = p->Next ) if( p->SeenFlag ) fprintf(installFile, "cp %s %s/fonts/%s/devipress\n", p->TargetName, LibraryDirectory, DeviceName); fprintf(installFile, "cp DESC %s/fonts/%s/devipress\n", LibraryDirectory, DeviceName); fprintf(installFile, "cp %s %s/fonts/%s/devipress\n", FONTMAPFILENAME, LibraryDirectory, DeviceName); fprintf(installFile, "cd %s/fonts/%s/devipress\n", LibraryDirectory, DeviceName); (void) fprintf(installFile, "makedev DESC\n"); (void) fprintf(installFile, "makextdev DESC\n"); (void) fclose(installFile); (void) chmod(INSTALLNAME, 0755); } /* * write a file that rm's all the files created by this program */ private WriteCleanUpFile(configChain) struct FontConfig *configChain; { FILE *cleanupFile; struct FontConfig *p; if( (cleanupFile = fopen(CLEANUPNAME, "w")) == NULL ) { fprintf(stderr, "can't open the file 'cleanup' for writing\n"); return; } fprintf(cleanupFile, "#! /bin/sh\n"); for( p = configChain; p != NULL; p = p->Next ) if( p->SeenFlag ) fprintf(cleanupFile, "rm %s\n", p->TargetName); fprintf(cleanupFile, "rm DESC\n"); fprintf(cleanupFile, "rm %s\n", INSTALLNAME); fprintf(cleanupFile, "rm %s\n", FONTMAPFILENAME); fprintf(cleanupFile, "rm %s\n", CLEANUPNAME); (void) fclose(cleanupFile); (void) chmod(CLEANUPNAME, 0755); } /* * called once per font on the stack */ public PerTroffFont(configChain, fontDescVec) struct FontConfig *configChain; unsigned char *fontDescVec; { unsigned char *charMetricsProperty, *metricsProperty, *width, *charMetric; char iSender[MAXTOKENSIZE], iCharName[MAXTOKENSIZE], fileType[MAXTOKENSIZE], *fontName[3], iCharSet[MAXTOKENSIZE], iCharCode[MAXTOKENSIZE]; FILE *descFile, *modelFile; struct FontConfig *p; struct TokenState *ts; int charSet, charNumber, charIndex, xWidth; if( !GetFontNameProperty(fontDescVec, fontName) ) { fprintf(stderr, "ipmetrics: can't get font name\n"); return; } if( (charMetricsProperty = GetStringProp("characterMetrics", fontDescVec)) == NULL ) { printf("ipmetrics: can't find 'characterMetrics' property\n"); return; } for( p = configChain; p != NULL; p = p->Next ) { if( !(strcmp(p->FontPt1, fontName[0]) == 0 && strcmp(p->FontPt2, fontName[1]) == 0 && strcmp(p->FontPt3, fontName[2]) == 0) ) continue; if( (descFile = fopen(p->TargetName , "w")) == NULL ) { printf("ipmetrics: can't open %s for writing\n", p->TargetName); return;} printf("\t%s\n", p->TargetName); if( (modelFile = fopen(p->MapFile, "r")) == NULL ) { printf("ipmetrics: can't open %s for reading\n", p->MapFile); return;} p->SeenFlag = TRUE; FontCount++; ts = InitTokenStream(modelFile); fprintf(descFile, "#\n"); fprintf(descFile, "# %s/%s/%s for Interpress device %s\n", p->FontPt1, p->FontPt2, p->FontPt3, DeviceName); fprintf(descFile, "name %s\n", p->TargetName); fprintf(descFile, "internalname %d\n", FontCount); GetToken(ts, fileType, MAXTOKENSIZE); if( strcmp(fileType, "special") == 0 ) fprintf(descFile, "special\n"); else ProcessTroffLigatures(charMetricsProperty, descFile); fprintf(descFile, "charset\n"); while( !EndOfFile(ts) ) { GetToken(ts, iCharSet, MAXTOKENSIZE); if( sscanf(iCharSet, "%o", &charSet) != 1 ) printf("ipmetrics: couldn't convert iCharSet number. Token was: %s\n", iCharSet); if( EndOfLine(ts) ) { printf("ipmetrics: premature end of line in map file: %s!\n", p->MapFile); printf("\tlast token was iCharSet: `%s'\n", iCharSet); continue; } GetToken(ts, iCharCode, MAXTOKENSIZE); if( sscanf(iCharCode, "%o", &charNumber) != 1 ) printf("ipmetrics: couldn't convert iCharCode. Token was: %s\n", iCharCode); if( EndOfLine(ts) ) { printf("ipmetrics: premature end of line in map file: %s!\n", p->MapFile); printf("\tlast token was iCharCode: `%s'\n", iCharCode); continue; } GetToken(ts, iSender, MAXTOKENSIZE); if( EndOfLine(ts) ) { printf("ipmetrics: premature end of line in map file: %s!\n", p->MapFile); printf("\tlast token was iSender: `%s'\n", iSender); continue; } GetToken(ts, iCharName, MAXTOKENSIZE); charIndex = Make16BitChar(charSet, charNumber); /* skip the rest of this loop if it's not in this font */ if( (charMetric = GetIntegerProp(charIndex, charMetricsProperty)) == NULL ) { EatRestOfLine(ts); continue; } if( (width = GetStringProp("widthX", charMetric)) == NULL ){ printf("ipmetrics: can't find widthX property of %d\n", charIndex); EatRestOfLine(ts); continue;} if( gettype(width) != type_number ) { printf("ipmetrics: width not of type number for %d\n", charIndex); EatRestOfLine(ts); continue;} if( getsubtype(width) != subtype_rational ) { printf("ipmetrics: width not of subtype rational for %d\n", charIndex); EatRestOfLine(ts); continue;} xWidth = (getnumerator(width)*UNITWIDTH*MICAS_PER_INCH + (getdenominator(width) * POINTS_PER_INCH)/2)/ (getdenominator(width) * POINTS_PER_INCH); if( xWidth >= 256 ) printf("ipmetrics: warning width >= 256\n"); fprintf(descFile, "%s\t%d\t%s\t", iCharName, xWidth, iSender); if( charIndex < 0377 ) fprintf(descFile, "%d\n", charIndex); else fprintf(descFile, "0377\t0%o\n", charIndex); CheckForSpecialness(iCharName); while( !EndOfLine(ts) ) { GetToken(ts, iCharName, MAXTOKENSIZE); fprintf(descFile, "%s\t\"\n", iCharName); CheckForSpecialness(iCharName);}} CloseTokenStream(ts); (void) fclose(descFile); (void) fclose(modelFile); } if( (metricsProperty = GetStringProp("metrics", fontDescVec)) != NULL ) { unsigned char *easyProperty; if( (easyProperty = GetStringProp("easy", metricsProperty)) != NULL ) ProcessEasy(easyProperty); } } /* * read the rest of the tokens off the current line */ EatRestOfLine(ts) struct TokenState *ts; { char byteBucket[MAXTOKENSIZE]; while( !EndOfLine(ts) ) GetToken(ts, byteBucket, MAXTOKENSIZE); } /* * assume that the font is in XC1-1-1 standard and find the ligatures * that troff wants */ private ProcessTroffLigatures(charMetricsVec, descFile) unsigned char *charMetricsVec; FILE *descFile; { char ligatureNames[21]; (void) strcpy(ligatureNames, ""); if( GetIntegerProp(Make16BitChar(0360, 044), charMetricsVec) != NULL ) (void) strcat(ligatureNames, " fi"); if( GetIntegerProp(Make16BitChar(0360, 045), charMetricsVec) != NULL ) (void) strcat(ligatureNames, " fl"); if( GetIntegerProp(Make16BitChar(0360, 041), charMetricsVec) != NULL ) (void) strcat(ligatureNames, " ff"); if( GetIntegerProp(Make16BitChar(0360, 042), charMetricsVec) != NULL ) (void) strcat(ligatureNames, " ffi"); if( GetIntegerProp(Make16BitChar(0360, 043), charMetricsVec) != NULL ) (void) strcat(ligatureNames, " ffl"); if( strcmp(ligatureNames, "") != 0 ) fprintf(descFile, "ligatures %s 0\n", ligatureNames);} /* * Check to see if a character is special and add it to the "charset" * in the DESC file if it is. */ private CheckForSpecialness(s) char *s; { /* right now, if it two characters long, then it must be special */ if( strlen(s) == 2 ) AddToCharSet(s); } /* * add a special character to the set of special characters. The set * is implemented as a linked list. */ private AddToCharSet(s) char *s; { struct CharElement **p, *q; p = &CharSet; while( *p != NULL ) { if( strcmp(s, (*p)->CharName) == 0 ) return; p = &(*p)->Next; } q = (struct CharElement *) malloc((unsigned) sizeof(struct CharElement)); (void) strcpy(q->CharName, s); q->Next = NULL; *p = q; } /* * print out the list of special characters to the DESC file */ private PrintCharSet(file) FILE *file; { int itemsPerLine, total; /* total number of special chars */ struct CharElement *p; /* test to see if there is a char. set. ditroff requires this! * you just can't have a null charset! */ if( CharSet == NULL ) return; fprintf(file, "charset\n"); itemsPerLine = 0; total = 0; for( p = CharSet; p != NULL; p = p->Next ) { fprintf(file, " %s", p->CharName); total++; if( itemsPerLine++ > 20 ) { (void) fputc('\n', file); itemsPerLine = 0; } } if( itemsPerLine != 0 ) (void) fputc('\n', file); printf("\tthere were %d special characters (out of a max of 221)\n", total); } /* * Process the "easy" property of the "metrics" property. This * will tell us what (viewing) sizes the font is available in. */ private ProcessEasy(easyProperty) unsigned char *easyProperty; { int depth, i; unsigned char **array; if( gettype(easyProperty) != type_vector || getsubtype(easyProperty) != subtype_general ) { printf("ipmetrics: wrong vector type in 'easy'\n"); return; } depth = getdepth(easyProperty); array = getvector(easyProperty); for( i = 0; i < depth; i++ ) { double *transform, fPointSize; int iPointSize; if( gettype(array[i]) != type_transformation ) { printf("ipmetrics: transforms not found in 'easy'\n"); return; } transform = gettransformation(array[i]); if( transform[0] != transform[4] ) { printf("ipmetrics: only square transforms in 'easy'\n"); return; } if( transform[1] != 0 || transform[2] != 0 || transform[3] != 0 || transform[5] != 0 ) { printf("ipmetrics: troff doesn't support rotations\n"); return; } fPointSize = transform[0]*72*100000/2540; iPointSize = fPointSize + 0.5; if( fabs(fPointSize - iPointSize) > .25 ) { printf("ipmetrics: troff doesn't support fractional points: %f6.2\n", fPointSize); return; } SetOfPointSizes[iPointSize] = 1; free((char *) transform); } free((char *) array); }