1: /* 2: * Copyright (c) 1984, 1985 Xerox Corp. 3: * Handle troff here 4: * 5: * note that Troff uses "fat points" of which there are exactly 72 per inch. 6: * 7: * HISTORY 8: * Nov, 1985 Lee Moore, Xerox Webster Research Center 9: * Created. 10: */ 11: 12: #include <stdio.h> 13: #include <math.h> 14: #include "stack.h" 15: #include "token.h" 16: #include "config.h" 17: #include "ipmetrics.h" 18: #include "troff.h" 19: 20: #define TRUE 1 21: #define FALSE 0 22: 23: 24: /* the following value should be choosen so that none of the widths 25: * is greater than 256 26: */ 27: #define UNITWIDTH 5 /* was 10 */ 28: 29: 30: #define MAXSPECIALNAMES 221 /* maximum number of special characters. 31: * this constant is fixed in Troff 32: */ 33: 34: #define public 35: #define private static 36: 37: public char *malloc(); 38: 39: public char *DeviceName, 40: *LibraryDirectory; 41: 42: struct CharElement { 43: struct CharElement *Next; 44: char CharName[3]; }; 45: 46: private struct CharElement *CharSet = NULL; 47: 48: private int SetOfPointSizes[MAXPOINTSIZE], 49: FontCount = 0; 50: 51: public 52: InitTroff() { 53: } 54: 55: public 56: CleanUpTroff(configChain) 57: struct FontConfig *configChain; { 58: struct FontConfig *p; 59: 60: WriteDescFile(configChain); 61: WriteFontMapFile(configChain); 62: WriteInstallFile(configChain); 63: WriteCleanUpFile(configChain); 64: 65: for( p = configChain; p != NULL; p = p->Next ) 66: if( !p->SeenFlag ) 67: printf("couldn't find: %s/%s/%s\n", 68: p->FontPt1, p->FontPt2, p->FontPt3); 69: } 70: 71: private 72: WriteDescFile(configChain) 73: struct FontConfig *configChain; { 74: int i; 75: FILE *deviceFile; 76: struct FontConfig *p; 77: 78: if( (deviceFile = fopen("DESC", "w")) == NULL ) { 79: printf("can't open 'DESC' for writing\n"); 80: exit(1); } 81: 82: /* output boiler plate */ 83: fprintf(deviceFile, "# describe the '%s' interpress device\n", DeviceName); 84: fprintf(deviceFile, "res %d\n", MICAS_PER_INCH); 85: fprintf(deviceFile, "hor 1\n"); 86: fprintf(deviceFile, "vert 1\n"); 87: fprintf(deviceFile, "unitwidth %d\n", UNITWIDTH); 88: fprintf(deviceFile, "paperwidth %d\n", PAGE_WIDTH_IN_MICAS); 89: fprintf(deviceFile, "paperlength %d\n", PAGE_HEIGHT_IN_MICAS); 90: 91: /* output sizes */ 92: fprintf(deviceFile, "sizes "); 93: 94: for( i = 1; i < MAXPOINTSIZE; i++ ) 95: if( SetOfPointSizes[i] ) 96: fprintf(deviceFile," %d", i); 97: 98: fprintf(deviceFile, " 0\n"); 99: 100: /* output fonts */ 101: fprintf(deviceFile, "fonts %d ", FontCount); 102: 103: for( p = configChain; p != NULL; p = p->Next ) 104: if( p->SeenFlag ) 105: fprintf(deviceFile, "%s ", p->TroffName); 106: 107: fprintf(deviceFile, "\n"); 108: PrintCharSet(deviceFile); 109: fclose(deviceFile); } 110: 111: 112: 113: private 114: WriteFontMapFile(configChain) 115: struct FontConfig *configChain; { 116: int i; 117: FILE *fontMapFile; 118: struct FontConfig *p; 119: 120: if( (fontMapFile = fopen(FONTMAPFILENAME, "w")) == NULL ) { 121: fprintf(stderr, "can't open the file '%s' for writing\n", FONTMAPFILENAME); 122: return; } 123: 124: for( p = configChain; p != NULL; p = p->Next ) 125: if( p->SeenFlag ) 126: fprintf(fontMapFile, "%s %s/%s/%s\n", p->TroffName, 127: p->FontPt1, p->FontPt2, p->FontPt3); 128: 129: fclose(fontMapFile); 130: chmod(FONTMAPFILENAME, 0755); } 131: 132: 133: private 134: WriteInstallFile(configChain) 135: struct FontConfig *configChain; { 136: int i; 137: FILE *installFile; 138: struct FontConfig *p; 139: 140: if( (installFile = fopen(INSTALLNAME, "w")) == NULL ) { 141: fprintf(stderr, "can't open the file 'install' for writing\n"); 142: return; } 143: 144: fprintf(installFile, "#! /bin/sh\n"); 145: fprintf(installFile, "if test ! -d %s/fonts/%s\n", LibraryDirectory, DeviceName); 146: fprintf(installFile, " then\n"); 147: fprintf(installFile, " mkdir %s/fonts/%s\n", LibraryDirectory, DeviceName); 148: fprintf(installFile, " fi\n"); 149: fprintf(installFile, "if test ! -d %s/fonts/%s/devipress\n", LibraryDirectory, DeviceName); 150: fprintf(installFile, " then\n"); 151: fprintf(installFile, " mkdir %s/fonts/%s/devipress\n", LibraryDirectory, DeviceName); 152: fprintf(installFile, " fi\n"); 153: 154: 155: for( p = configChain; p != NULL; p = p->Next ) 156: if( p->SeenFlag ) 157: fprintf(installFile, "cp %s %s/fonts/%s/devipress\n", 158: p->TroffName, LibraryDirectory, DeviceName); 159: 160: fprintf(installFile, "cp DESC %s/fonts/%s/devipress\n", LibraryDirectory, 161: DeviceName); 162: fprintf(installFile, "cp %s %s/fonts/%s/devipress\n", FONTMAPFILENAME, 163: LibraryDirectory, DeviceName); 164: fprintf(installFile, "cd %s/fonts/%s/devipress\n", LibraryDirectory, 165: DeviceName); 166: fprintf(installFile, "makedev DESC\n"); 167: fprintf(installFile, "makextdev DESC\n"); 168: fclose(installFile); 169: chmod(INSTALLNAME, 0755); } 170: 171: 172: /* 173: * write a file that rm's all the files created by this program 174: */ 175: 176: private 177: WriteCleanUpFile(configChain) 178: struct FontConfig *configChain; { 179: int i; 180: FILE *cleanupFile; 181: struct FontConfig *p; 182: 183: if( (cleanupFile = fopen(CLEANUPNAME, "w")) == NULL ) { 184: fprintf(stderr, "can't open the file 'cleanup' for writing\n"); 185: return; } 186: 187: fprintf(cleanupFile, "#! /bin/sh\n"); 188: 189: for( p = configChain; p != NULL; p = p->Next ) 190: if( p->SeenFlag ) 191: fprintf(cleanupFile, "rm %s\n", p->TroffName); 192: 193: fprintf(cleanupFile, "rm DESC\n"); 194: fprintf(cleanupFile, "rm %s\n", INSTALLNAME); 195: fprintf(cleanupFile, "rm %s\n", FONTMAPFILENAME); 196: fprintf(cleanupFile, "rm %s\n", CLEANUPNAME); 197: fclose(cleanupFile); 198: chmod(CLEANUPNAME, 0755); } 199: 200: /* 201: * called once per font on the stack 202: */ 203: 204: public 205: PerTroffFont(configChain, fontDescVec) 206: struct FontConfig *configChain; 207: unsigned char *fontDescVec; { 208: unsigned char *charMetricsProperty, 209: *metricsProperty, 210: *width, 211: *charMetric; 212: char iSender[MAXTOKENSIZE], 213: iCharName[MAXTOKENSIZE], 214: fileType[MAXTOKENSIZE], 215: *fontName[3], 216: iCharSet[MAXTOKENSIZE], 217: iCharCode[MAXTOKENSIZE]; 218: FILE *descFile, 219: *modelFile; 220: struct FontConfig *p; 221: struct TokenState *ts; 222: int charSet, 223: charNumber, 224: charIndex, 225: xWidth; 226: 227: if( !GetFontNameProperty(fontDescVec, fontName) ) { 228: fprintf(stderr, "ipmetrics: can't get font name\n"); 229: return; 230: } 231: 232: if( (charMetricsProperty = GetStringProp("characterMetrics", fontDescVec)) 233: == NULL ) { 234: printf("ipmetrics: can't find 'characterMetrics' property\n"); 235: return; } 236: 237: for( p = configChain; p != NULL; p = p->Next ) { 238: if( !(strcmp(p->FontPt1, fontName[0]) == 0 && 239: strcmp(p->FontPt2, fontName[1]) == 0 && 240: strcmp(p->FontPt3, fontName[2]) == 0) ) 241: continue; 242: 243: if( (descFile = fopen(p->TroffName , "w")) == NULL ) { 244: printf("ipmetrics: can't open %s for writing\n", p->TroffName); 245: return;} 246: 247: if( (modelFile = fopen(p->MapFile, "r")) == NULL ) { 248: printf("ipmetrics: can't open %s for reading\n", p->MapFile); 249: return;} 250: 251: p->SeenFlag = TRUE; 252: /* (void) strcpy(malloc((unsigned) 3), p->TroffName); */ 253: FontCount++; 254: 255: ts = InitTokenStream(modelFile); 256: 257: fprintf(descFile, "#\n"); 258: fprintf(descFile, "# %s/%s/%s for Interpress device %s\n", p->FontPt1, p->FontPt2, p->FontPt3, DeviceName); 259: fprintf(descFile, "name %s\n", p->TroffName); 260: fprintf(descFile, "internalname %d\n", FontCount); 261: 262: GetToken(ts, fileType, MAXTOKENSIZE); 263: 264: if( strcmp(fileType, "special") == 0 ) 265: fprintf(descFile, "special\n"); 266: else 267: ProcessTroffLigatures(charMetricsProperty, descFile); 268: 269: fprintf(descFile, "charset\n"); 270: 271: while( !EndOfFile(ts) ) { 272: GetToken(ts, iCharSet, MAXTOKENSIZE); 273: sscanf(iCharSet, "%o", &charSet); 274: GetToken(ts, iCharCode, MAXTOKENSIZE); 275: sscanf(iCharCode, "%o", &charNumber); 276: GetToken(ts, iSender, MAXTOKENSIZE); 277: GetToken(ts, iCharName, MAXTOKENSIZE); 278: charIndex = Make16BitChar(charSet, charNumber); 279: 280: /* skip the rest of this loop if it's not in this font */ 281: if( (charMetric = 282: GetIntegerProp(charIndex, charMetricsProperty)) == NULL ) 283: continue; 284: 285: if( (width = GetStringProp("widthX", charMetric)) == NULL ){ 286: printf("ipmetrics: can't find widthX property of %d\n", 287: charIndex); 288: continue;} 289: 290: if( gettype(width) != type_number ) { 291: printf("ipmetrics: width not of type number for %d\n", 292: charIndex); 293: continue;} 294: 295: if( getsubtype(width) != subtype_rational ) { 296: printf("ipmetrics: width not of subtype number for %d\n", 297: charIndex); 298: continue;} 299: 300: xWidth = (getnumerator(width)*UNITWIDTH*MICAS_PER_INCH + 301: (getdenominator(width) * POINTS_PER_INCH)/2)/ 302: (getdenominator(width) * POINTS_PER_INCH); 303: 304: if( xWidth >= 256 ) 305: printf("ipmetrics: warning width >= 256\n"); 306: 307: fprintf(descFile, "%s\t%d\t%s\t", iCharName, xWidth, 308: iSender); 309: 310: if( charIndex < 0377 ) 311: fprintf(descFile, "%d\n", charIndex); 312: else 313: fprintf(descFile, "0377\t0%o\n", charIndex); 314: 315: CheckForSpecialness(iCharName); 316: 317: while( !EndOfLine(ts) ) { 318: GetToken(ts, iCharName, MAXTOKENSIZE); 319: fprintf(descFile, "%s\t\"\n", iCharName); 320: CheckForSpecialness(iCharName);}} 321: 322: CloseTokenStream(ts); 323: fclose(descFile); 324: fclose(modelFile); 325: } 326: 327: if( (metricsProperty = GetStringProp("metrics", fontDescVec)) 328: != NULL ) { 329: unsigned char *easyProperty; 330: 331: if( (easyProperty = GetStringProp("easy", metricsProperty)) 332: != NULL ) 333: ProcessEasy(easyProperty); 334: } 335: } 336: 337: /* 338: * assume that the font is in XC1-1-1 standard and find the ligatures 339: * that troff wants 340: */ 341: 342: private 343: ProcessTroffLigatures(charMetricsVec, descFile) 344: unsigned char *charMetricsVec; 345: FILE *descFile; { 346: char ligatureNames[21]; 347: 348: (void) strcpy(ligatureNames, ""); 349: 350: if( GetIntegerProp(Make16BitChar(0360, 044), charMetricsVec) != NULL ) 351: (void) strcat(ligatureNames, " fi"); 352: 353: if( GetIntegerProp(Make16BitChar(0360, 045), charMetricsVec) != NULL ) 354: (void) strcat(ligatureNames, " fl"); 355: 356: if( GetIntegerProp(Make16BitChar(0360, 041), charMetricsVec) != NULL ) 357: (void) strcat(ligatureNames, " ff"); 358: 359: if( GetIntegerProp(Make16BitChar(0360, 042), charMetricsVec) != NULL ) 360: (void) strcat(ligatureNames, " ffi"); 361: 362: if( GetIntegerProp(Make16BitChar(0360, 043), charMetricsVec) != NULL ) 363: (void) strcat(ligatureNames, " ffl"); 364: 365: if( strcmp(ligatureNames, "") != 0 ) 366: fprintf(descFile, "ligatures %s 0\n", ligatureNames);} 367: 368: /* 369: * Check to see if a character is special and add it to the "charset" 370: * in the DESC file if it is. 371: */ 372: 373: private 374: CheckForSpecialness(s) 375: char *s; { 376: /* right now, if it two characters long, then it must be special */ 377: if( strlen(s) == 2 ) 378: AddToCharSet(s); } 379: 380: /* 381: * add a special character to the set of special characters. The set 382: * is implemented as a linked list. 383: */ 384: 385: private 386: AddToCharSet(s) 387: char *s; { 388: struct CharElement **p, 389: *q; 390: 391: p = &CharSet; 392: 393: while( *p != NULL ) { 394: if( strcmp(s, (*p)->CharName) == 0 ) 395: return; 396: 397: p = &(*p)->Next; } 398: 399: q = (struct CharElement *) malloc((unsigned) sizeof(struct CharElement)); 400: (void) strcpy(q->CharName, s); 401: q->Next = NULL; 402: *p = q; } 403: 404: /* 405: * print out the list of special characters to the DESC file 406: */ 407: 408: private 409: PrintCharSet(file) 410: FILE *file; { 411: int itemsPerLine; 412: struct CharElement *p; 413: 414: /* test to see if there is a char. set. ditroff requires this! 415: * you just can't have a null charset! */ 416: if( CharSet == NULL ) 417: return; 418: 419: fprintf(file, "charset\n"); 420: itemsPerLine = 0; 421: 422: for( p = CharSet; p != NULL; p = p->Next ) { 423: fprintf(file, " %s", p->CharName); 424: 425: if( itemsPerLine++ > 20 ) { 426: fputc('\n', file); 427: itemsPerLine = 0; } } 428: 429: if( itemsPerLine != 0 ) 430: fputc('\n', file); } 431: 432: /* 433: * Process the "easy" property of the "metrics" property. This 434: * will tell us what (viewing) sizes the font is available in. 435: */ 436: 437: private 438: ProcessEasy(easyProperty) 439: unsigned char *easyProperty; { 440: int depth, 441: i; 442: unsigned char **array; 443: 444: if( gettype(easyProperty) != type_vector || 445: getsubtype(easyProperty) != subtype_general ) { 446: printf("ipmetrics: wrong vector type in 'easy'\n"); 447: return; } 448: 449: depth = getdepth(easyProperty); 450: array = getvector(easyProperty); 451: 452: for( i = 0; i < depth; i++ ) { 453: double *transform, 454: fPointSize; 455: int iPointSize; 456: 457: if( gettype(array[i]) != type_transformation ) { 458: printf("ipmetrics: transforms not found in 'easy'\n"); 459: return; } 460: 461: transform = gettransformation(array[i]); 462: 463: if( transform[0] != transform[4] ) { 464: printf("ipmetrics: only square transforms in 'easy'\n"); 465: return; } 466: 467: if( transform[1] != 0 || transform[2] != 0 || 468: transform[3] != 0 || transform[5] != 0 ) { 469: printf("ipmetrics: troff doesn't support rotations\n"); 470: return; } 471: 472: fPointSize = transform[0]*72*100000/2540; 473: iPointSize = fPointSize + 0.5; 474: 475: if( fabs(fPointSize - iPointSize) > .25 ) { 476: printf("ipmetrics: troff doesn't support fractional points: %f6.2\n", fPointSize); 477: return; } 478: 479: SetOfPointSizes[iPointSize] = 1; 480: free((char *) transform); 481: } 482: 483: free((char *) array); 484: }