1*34114Skarels #ifndef lint 2*34114Skarels static char Notice[] = "Copyright (c) 1985 Adobe Systems Incorporated"; 3*34114Skarels static char *RCSID="$Header: pscatmap.c,v 2.1 85/11/24 11:50:07 shore Rel $"; 4*34114Skarels #endif 5*34114Skarels /* pscatmap.c 6*34114Skarels * 7*34114Skarels * Copyright (C) 1985 Adobe Systems Incorporated 8*34114Skarels * 9*34114Skarels * Build font width files for troff and correspondence tables 10*34114Skarels * for pscat. 11*34114Skarels * 12*34114Skarels * Edit History: 13*34114Skarels * Andrew Shore: Sat Nov 9 15:37:04 1985 14*34114Skarels * End Edit History. 15*34114Skarels * 16*34114Skarels * The correspondence tables are intended to be created by humans for 17*34114Skarels * describing a set of 4 fonts to be used by troff: detailing the 18*34114Skarels * mapping from troff & C/A/T codes to output actions for pscat 19*34114Skarels * These actions take one of three forms: 20*34114Skarels * PFONT - map to a character in a PostScript font 21*34114Skarels * PLIG - map to a "fake" ligature 22*34114Skarels * PPROC - map to a named PostScript procedure 23*34114Skarels * PNONE - no action 24*34114Skarels * 25*34114Skarels * PFONT is straightforward, the mapping specifies which character in 26*34114Skarels * which PostScript font is desired and the character width is 27*34114Skarels * collected from the PostScript "afm" font metrics file format. 28*34114Skarels * Note that ascender and descender information is "wired in" to the code; 29*34114Skarels * it might be a better idea to "compute" it from the character 30*34114Skarels * bounding box information. 31*34114Skarels * 32*34114Skarels * PLIG is provided so that the correct width for the ligature may 33*34114Skarels * be "computed" by this program, rather than hand done by the user. 34*34114Skarels * There are 3 ligature types: 35*34114Skarels * 0126 - build "ff" out of "f" and "f" 36*34114Skarels * 0131 - build "ffi" out of "f" and "fi" 37*34114Skarels * 0130 - build "ffl" out of "f" and "fl" 38*34114Skarels * This list should probably be expanded to span the space. 39*34114Skarels * 40*34114Skarels * PPROC provides a general callback mechanism so that users can 41*34114Skarels * create and character definition with a PostScript procedure. 42*34114Skarels * The procedures are "named" with user-specified numbers, and are 43*34114Skarels * called with all information available to them (current position, 44*34114Skarels * font size, intended width, railmag, ...). Such procedures are used 45*34114Skarels * for troff characters not in any PostScript font (rules, boxes, 46*34114Skarels * constructed braces, etc.), but may also be used as a general 47*34114Skarels * "escape hatch" for incorporating ANY PostScript routine into a 48*34114Skarels * troff document -- a logo, a scanned image, etc. The exact 49*34114Skarels * calling rules are: 50*34114Skarels * an absolute moveto is performed to the position for this character 51*34114Skarels * The following numbers are pushed on the PS stack: 52*34114Skarels * pointsize 53*34114Skarels * troff character code 54*34114Skarels * "railmag" 55*34114Skarels * character width 56*34114Skarels * procedure "number" 57*34114Skarels * x offset 58*34114Skarels * y offset 59*34114Skarels * width 60*34114Skarels * 61*34114Skarels * then a procedure named "PSn" where n is the procedure number 62*34114Skarels * is executed. It is that procedure's responsibility to image 63*34114Skarels * the character and move by the appropriate width. 64*34114Skarels * 65*34114Skarels * RCSLOG: 66*34114Skarels * $Log: pscatmap.c,v $ 67*34114Skarels * Revision 2.1 85/11/24 11:50:07 shore 68*34114Skarels * Product Release 2.0 69*34114Skarels * 70*34114Skarels * Revision 1.3 85/11/20 00:32:45 shore 71*34114Skarels * support for System V 72*34114Skarels * short names, non ".c" output, better arith. 73*34114Skarels * 74*34114Skarels * Revision 1.2 85/05/14 11:24:04 shore 75*34114Skarels * 76*34114Skarels * 77*34114Skarels * 78*34114Skarels */ 79*34114Skarels 80*34114Skarels #include <stdio.h> 81*34114Skarels #ifdef SYSV 82*34114Skarels #include <string.h> 83*34114Skarels #else 84*34114Skarels #include <strings.h> 85*34114Skarels #endif 86*34114Skarels #include "transcript.h" 87*34114Skarels #include "action.h" 88*34114Skarels 89*34114Skarels #define LFONT 1 90*34114Skarels #define LMAP 2 91*34114Skarels #define LNONE 3 92*34114Skarels 93*34114Skarels private char linebuf[200]; 94*34114Skarels private char *libdir; /* place for AFM files */ 95*34114Skarels 96*34114Skarels private struct chAction chAction [] = { 97*34114Skarels PFONT, "PFONT", /* character in PostScript font */ 98*34114Skarels PLIG, "PLIG", /* fake ligatures: ff ffi ffl */ 99*34114Skarels PPROC, "PPROC", /* PostScript procedure outcall */ 100*34114Skarels PNONE, "0", /* null action */ 101*34114Skarels 0, 0 102*34114Skarels }; 103*34114Skarels 104*34114Skarels #define MAXFONTS 25 105*34114Skarels private int nfonts; 106*34114Skarels private struct font { 107*34114Skarels char mapname[20]; /* short name in map file e.g., "ROMAN" */ 108*34114Skarels char afmname[80]; /* name of AFM file for this font (in map file) */ 109*34114Skarels char psname[80]; /* PS font name from AFM file */ 110*34114Skarels int widths[256]; /* PostScript widths of encoded chars (1000/em) */ 111*34114Skarels /* more here */ 112*34114Skarels } fonts[MAXFONTS]; 113*34114Skarels private char faces[] = "RIBS0"; /* order important! */ 114*34114Skarels 115*34114Skarels private char familyname[80]; 116*34114Skarels private char facenames[4][80]; 117*34114Skarels 118*34114Skarels /* there should be on the order of 4 * 128 characters, so 1000 is generous */ 119*34114Skarels 120*34114Skarels #define MAXCHARS 1000 121*34114Skarels private struct ctab { 122*34114Skarels int trcode; /* troff char code */ 123*34114Skarels int catcode; /* CAT char code */ 124*34114Skarels int wid; /* table-driven width */ 125*34114Skarels int action; /* action type */ 126*34114Skarels int x, y; /* x and y offset */ 127*34114Skarels int font; /* PostScript font */ 128*34114Skarels int pschar; /* PS character code */ 129*34114Skarels int pswidth; /* PS width (/1000) */ 130*34114Skarels char *descr; /* short print description */ 131*34114Skarels } ctab[MAXCHARS]; 132*34114Skarels private int nchars; 133*34114Skarels 134*34114Skarels 135*34114Skarels private BuildTable() 136*34114Skarels { 137*34114Skarels char *c; 138*34114Skarels int status; 139*34114Skarels int gotfamily, gotfaces, gotfonts, gotmap; 140*34114Skarels 141*34114Skarels gotfamily = gotfaces = gotfonts = gotmap = 0; 142*34114Skarels 143*34114Skarels while(fgets(linebuf, sizeof linebuf, stdin) != NULL) { 144*34114Skarels /* strip off newline */ 145*34114Skarels if ((c = INDEX(linebuf, '\n')) == 0) { 146*34114Skarels fprintf(stderr, "line too long \"%s\"\n",linebuf); 147*34114Skarels exit(1); 148*34114Skarels } 149*34114Skarels *c = '\0'; 150*34114Skarels /* ignore blank or comment (%) lines */ 151*34114Skarels if ((*linebuf == '%') || (*linebuf == '\0')) continue; 152*34114Skarels if (*linebuf == '@') { 153*34114Skarels /* "command" line */ 154*34114Skarels /* printf("C: %s\n", linebuf); */ 155*34114Skarels if (strncmp(&linebuf[1], "FAMILYNAME", 10) == 0) { 156*34114Skarels if (sscanf(linebuf,"@FAMILYNAME %s",familyname) != 1) { 157*34114Skarels fprintf(stderr,"bad familyname %s\n",familyname); 158*34114Skarels exit(1); 159*34114Skarels } 160*34114Skarels gotfamily++; 161*34114Skarels } 162*34114Skarels if (strncmp(&linebuf[1], "FACENAMES", 9) == 0) { 163*34114Skarels if (sscanf(linebuf,"@FACENAMES %s %s %s %s", 164*34114Skarels facenames[0],facenames[1], 165*34114Skarels facenames[2],facenames[3]) != 4) { 166*34114Skarels fprintf(stderr,"must be four facenames\n"); 167*34114Skarels exit(1); 168*34114Skarels } 169*34114Skarels gotfaces++; 170*34114Skarels } 171*34114Skarels if (strcmp(&linebuf[1], "BEGINFONTS") == 0) { 172*34114Skarels if ((!gotfamily) || (!gotfaces)) { 173*34114Skarels fprintf(stderr,"FAMILYNAME and FACENAMES must come before BEGINFONTS\n"); 174*34114Skarels exit(1); 175*34114Skarels } 176*34114Skarels VOIDC strcpy(fonts[0].mapname,"0"); 177*34114Skarels VOIDC strcpy(fonts[0].afmname,"0"); 178*34114Skarels VOIDC strcpy(fonts[0].psname,"0"); 179*34114Skarels nfonts = 1; 180*34114Skarels status = LFONT; 181*34114Skarels continue; 182*34114Skarels } 183*34114Skarels if (strcmp(&linebuf[1], "ENDFONTS") == 0) { 184*34114Skarels gotfonts++; 185*34114Skarels status = LNONE; 186*34114Skarels continue; 187*34114Skarels } 188*34114Skarels if (strcmp(&linebuf[1], "BEGINMAP") == 0) { 189*34114Skarels if (!gotfonts) { 190*34114Skarels fprintf(stderr,"BEGINFONTS/ENDFONTS must come before map\n"); 191*34114Skarels exit(1); 192*34114Skarels } 193*34114Skarels status = LMAP; 194*34114Skarels continue; 195*34114Skarels } 196*34114Skarels if (strcmp(&linebuf[1], "ENDMAP") == 0) { 197*34114Skarels status = LNONE; 198*34114Skarels gotmap++; 199*34114Skarels continue; 200*34114Skarels } 201*34114Skarels } 202*34114Skarels switch (status) { 203*34114Skarels case LFONT: 204*34114Skarels GetFont(); 205*34114Skarels break; 206*34114Skarels case LMAP: 207*34114Skarels GetMap(); 208*34114Skarels break; 209*34114Skarels default: 210*34114Skarels break; 211*34114Skarels } 212*34114Skarels } 213*34114Skarels if (!gotmap) { 214*34114Skarels fprintf(stderr,"missing @ENDMAP\n"); 215*34114Skarels exit(1); 216*34114Skarels } 217*34114Skarels } 218*34114Skarels 219*34114Skarels private GetFont () { 220*34114Skarels char *eqp; 221*34114Skarels register int i; 222*34114Skarels char afmpath[200]; 223*34114Skarels #ifdef SYSV 224*34114Skarels char shortname[40]; 225*34114Skarels #endif 226*34114Skarels 227*34114Skarels if ((eqp = INDEX(linebuf, '=')) == 0) { 228*34114Skarels fprintf(stderr, "bad FONTS line:%s\n",linebuf); 229*34114Skarels exit(1); 230*34114Skarels } 231*34114Skarels *eqp++ = '\0'; 232*34114Skarels for (i = 0; i < nfonts; i++) { 233*34114Skarels if (strcmp (fonts[i].mapname, linebuf) == 0) { 234*34114Skarels fprintf(stderr, "duplicate entry for font %s\n", linebuf); 235*34114Skarels exit(1); 236*34114Skarels } 237*34114Skarels } 238*34114Skarels if (nfonts >= MAXFONTS) { 239*34114Skarels fprintf(stderr, "Too many FONTS\n"); 240*34114Skarels exit(1); 241*34114Skarels } 242*34114Skarels if (strlen(linebuf) > (sizeof fonts[0].mapname)) { 243*34114Skarels fprintf(stderr, "FONT name too long %s\n", linebuf); 244*34114Skarels exit(1); 245*34114Skarels } 246*34114Skarels if (strlen(eqp) > (sizeof fonts[0].afmname)) { 247*34114Skarels fprintf(stderr, "FONT name too long %s\n", eqp); 248*34114Skarels exit(1); 249*34114Skarels } 250*34114Skarels VOIDC strcpy(fonts[nfonts].mapname, linebuf); 251*34114Skarels VOIDC strcpy(fonts[nfonts].afmname, eqp); 252*34114Skarels 253*34114Skarels /* read the font's .afm file to get real widths */ 254*34114Skarels if (*eqp == '/') { 255*34114Skarels VOIDC strcpy(afmpath,eqp); 256*34114Skarels } 257*34114Skarels else { 258*34114Skarels VOIDC strcpy(afmpath,libdir); 259*34114Skarels VOIDC strcat(afmpath,"/"); 260*34114Skarels #ifdef SYSV 261*34114Skarels mapname(eqp,shortname); 262*34114Skarels VOIDC strcat(afmpath,shortname); 263*34114Skarels #else 264*34114Skarels VOIDC strcat(afmpath, eqp); 265*34114Skarels #endif 266*34114Skarels VOIDC strcat(afmpath,".afm"); 267*34114Skarels } 268*34114Skarels ReadAFM(afmpath); 269*34114Skarels nfonts++; 270*34114Skarels return; 271*34114Skarels } 272*34114Skarels 273*34114Skarels 274*34114Skarels private ReadAFM(afmfile) char *afmfile; { 275*34114Skarels char *c; 276*34114Skarels FILE *afm; 277*34114Skarels int gotMetrics, gotName, inChars, ccode, cwidth; 278*34114Skarels char afmbuf[1000]; 279*34114Skarels 280*34114Skarels if ((afm = fopen(afmfile, "r")) == NULL) { 281*34114Skarels fprintf(stderr,"Can't open afm file %s\n",afmfile); 282*34114Skarels exit(1); 283*34114Skarels } 284*34114Skarels inChars = gotMetrics = gotName = 0; 285*34114Skarels while(fgets(afmbuf, sizeof afmbuf, afm) != NULL) { 286*34114Skarels /* strip off newline */ 287*34114Skarels if ((c = INDEX(afmbuf, '\n')) == 0) { 288*34114Skarels fprintf(stderr, "AFM line too long %s\n", afmbuf); 289*34114Skarels exit(1); 290*34114Skarels } 291*34114Skarels *c = '\0'; 292*34114Skarels /* ignore blank lines */ 293*34114Skarels if (*afmbuf == '\0') continue; 294*34114Skarels if (strcmp(afmbuf,"StartFontMetrics 1.0") == 0) { 295*34114Skarels gotMetrics++; 296*34114Skarels continue; 297*34114Skarels } 298*34114Skarels if (strncmp(afmbuf,"FontName ", 9) == 0) { 299*34114Skarels VOIDC sscanf(afmbuf,"FontName %s",fonts[nfonts].psname); 300*34114Skarels gotName++; 301*34114Skarels continue; 302*34114Skarels } 303*34114Skarels if (strcmp(afmbuf,"EndCharMetrics") == 0) { 304*34114Skarels if (!inChars) { 305*34114Skarels fprintf(stderr,"AFM: %s without StartCharMetrics\n",afmbuf); 306*34114Skarels exit(1); 307*34114Skarels } 308*34114Skarels inChars++; 309*34114Skarels break; 310*34114Skarels } 311*34114Skarels if (strcmp(afmbuf,"StartCharMetrics") == 0) { 312*34114Skarels inChars++; 313*34114Skarels continue; 314*34114Skarels } 315*34114Skarels if (inChars == 1) { 316*34114Skarels if (sscanf(afmbuf,"C %d ; WX %d ;",&ccode, &cwidth) != 2) { 317*34114Skarels fprintf(stderr, "Bad Character in AFM file %s\n",afmbuf); 318*34114Skarels exit(1); 319*34114Skarels } 320*34114Skarels if (ccode == -1) continue; /* skip unencoded chars */ 321*34114Skarels if (ccode > 255) { 322*34114Skarels fprintf(stderr, "Bad Character Code skipped %s\n", afmbuf); 323*34114Skarels continue; 324*34114Skarels } 325*34114Skarels fonts[nfonts].widths[ccode] = cwidth; 326*34114Skarels continue; 327*34114Skarels } 328*34114Skarels } 329*34114Skarels if ((inChars != 2) || (!gotMetrics) || (!gotName)) { 330*34114Skarels fprintf(stderr,"improper AFM file %s\n",afmfile); 331*34114Skarels exit(1); 332*34114Skarels } 333*34114Skarels VOIDC fclose(afm); 334*34114Skarels } 335*34114Skarels 336*34114Skarels 337*34114Skarels private GetMap(){ 338*34114Skarels int trcode; 339*34114Skarels char trfont; 340*34114Skarels int catcode; 341*34114Skarels int wid; 342*34114Skarels char action[10]; 343*34114Skarels int x,y; 344*34114Skarels char psfont[20]; 345*34114Skarels int pschar; 346*34114Skarels char descr[100]; 347*34114Skarels 348*34114Skarels char *fp; 349*34114Skarels int trface; /* 0 - 3 : R I B S */ 350*34114Skarels int pf; 351*34114Skarels struct ctab *ch; 352*34114Skarels struct chAction *act; 353*34114Skarels 354*34114Skarels if (sscanf(linebuf,"%o %c %o %d %s %d %d %s %o \"%[^\"]\"", 355*34114Skarels &trcode, &trfont, &catcode, &wid, action, &x, &y, 356*34114Skarels psfont, &pschar, descr) != 10) { 357*34114Skarels fprintf(stderr,"Bad line %s",linebuf); 358*34114Skarels } 359*34114Skarels 360*34114Skarels /* verify the integrity of the data we got */ 361*34114Skarels if ((fp = INDEX(faces, trfont)) == 0) { 362*34114Skarels fprintf(stderr, "Bad face code in %s\n", linebuf); 363*34114Skarels exit(1); 364*34114Skarels } 365*34114Skarels trface = fp - faces; 366*34114Skarels for (act = chAction; act->actName != 0; act++) { 367*34114Skarels if (strcmp(action, act->actName) == 0) break; 368*34114Skarels } 369*34114Skarels if (act->actName == 0) { 370*34114Skarels fprintf(stderr, "Bad action in %s\n", linebuf); 371*34114Skarels exit(1); 372*34114Skarels } 373*34114Skarels for (pf = 0; pf < nfonts; pf++) { 374*34114Skarels if (strcmp(fonts[pf].mapname, psfont) == 0) goto gotfont; 375*34114Skarels } 376*34114Skarels fprintf(stderr, "Bad font (%s) name %s\n", linebuf, psfont); 377*34114Skarels exit(1); 378*34114Skarels 379*34114Skarels gotfont: 380*34114Skarels 381*34114Skarels if (nchars >= MAXCHARS) { 382*34114Skarels fprintf(stderr,"Too many character definitions\n"); 383*34114Skarels exit(1); 384*34114Skarels } 385*34114Skarels ch = &ctab[nchars]; 386*34114Skarels ch->trcode = trcode; 387*34114Skarels ch->catcode = (trface << 7) | catcode; 388*34114Skarels ch->action = act->actCode; 389*34114Skarels ch->x = x; 390*34114Skarels ch->y = y; 391*34114Skarels ch->font = pf; 392*34114Skarels ch->pschar = pschar; 393*34114Skarels if (descr[0]) { 394*34114Skarels if ((ch->descr = malloc((unsigned) (strlen(descr)+1))) == NULL) { 395*34114Skarels fprintf(stderr,"malloc failed\n"); 396*34114Skarels exit(1); 397*34114Skarels } 398*34114Skarels VOIDC strcpy(ch->descr, descr); 399*34114Skarels } 400*34114Skarels 401*34114Skarels /* calculate width in cat units (432 per inch) of 6 pt 402*34114Skarels * character (the way troff wants them). 403*34114Skarels * 6 pts = 36 cat units 404*34114Skarels */ 405*34114Skarels 406*34114Skarels if (ch->action == PLIG) {/* fake ligature, fake width */ 407*34114Skarels switch (catcode) { 408*34114Skarels case 0126: /* ff = f f */ 409*34114Skarels ch->pswidth = fonts[pf].widths['f'] * 2; 410*34114Skarels break; 411*34114Skarels case 0131: /* ffi = f fi */ 412*34114Skarels ch->pswidth = fonts[pf].widths['f'] + fonts[pf].widths[0256]; 413*34114Skarels break; 414*34114Skarels case 0130: /* ffl = f fl */ 415*34114Skarels ch->pswidth = fonts[pf].widths['f'] + fonts[pf].widths[0257]; 416*34114Skarels break; 417*34114Skarels default: 418*34114Skarels fprintf(stderr,"Unknown ligature 0%o\n",catcode); 419*34114Skarels exit(1); 420*34114Skarels } 421*34114Skarels } 422*34114Skarels else { 423*34114Skarels ch->pswidth = fonts[pf].widths[pschar]; 424*34114Skarels } 425*34114Skarels ch->wid = (wid >= 0) ? wid : 426*34114Skarels (int) ( (((float) ch->pswidth * 36.0 ) / 1000.0) + 0.5); 427*34114Skarels if (ch->wid > 255) { 428*34114Skarels fprintf(stderr,"Scaled width too big!\n"); 429*34114Skarels exit(1); 430*34114Skarels } 431*34114Skarels nchars++; 432*34114Skarels } 433*34114Skarels 434*34114Skarels 435*34114Skarels private int compCTent(a,b) 436*34114Skarels struct ctab *a, *b; 437*34114Skarels { 438*34114Skarels if (a->catcode < b->catcode) return -1; 439*34114Skarels if (a->catcode > b->catcode) return 1; 440*34114Skarels return 0; 441*34114Skarels } 442*34114Skarels 443*34114Skarels 444*34114Skarels private WriteTable() { 445*34114Skarels int i, curcode; 446*34114Skarels struct ctab *ct; 447*34114Skarels struct map map, emptymap; 448*34114Skarels char outname[84]; 449*34114Skarels FILE *mapfile; 450*34114Skarels 451*34114Skarels /* write out font mapping */ 452*34114Skarels if (familyname[0] == 0) { 453*34114Skarels fprintf(stderr,"No FAMILYNAME specified!\n"); 454*34114Skarels exit(1); 455*34114Skarels } 456*34114Skarels VOIDC strcpy(outname, familyname); 457*34114Skarels VOIDC strcat(outname, ".ct"); 458*34114Skarels if ((mapfile = fopen(outname, "w")) == NULL) { 459*34114Skarels fprintf(stderr,"can't open output file %s\n", mapfile); 460*34114Skarels exit(1); 461*34114Skarels } 462*34114Skarels VOIDC putw(nfonts, mapfile); 463*34114Skarels for (i = 0; i < nfonts; i++) { 464*34114Skarels VOIDC fwrite(fonts[i].psname, sizeof fonts[0].psname, 1, mapfile); 465*34114Skarels } 466*34114Skarels /* sort ctab by catcode */ 467*34114Skarels qsort((char *) ctab, nchars, sizeof (struct ctab), compCTent); 468*34114Skarels /* write it out */ 469*34114Skarels VOIDC putw(ctab[nchars-1].catcode,mapfile); 470*34114Skarels VOIDC fflush(mapfile); 471*34114Skarels emptymap.wid = emptymap.x = emptymap.y = emptymap.font = 472*34114Skarels emptymap.pschar = emptymap.action = emptymap.pswidth = 0; 473*34114Skarels 474*34114Skarels ct = &ctab[0]; 475*34114Skarels curcode = 0; 476*34114Skarels for (i = 0; i < MAXCHARS; i++) { 477*34114Skarels while (curcode < ct->catcode) { 478*34114Skarels VOIDC write(fileno(mapfile), &emptymap, sizeof map); 479*34114Skarels curcode++; 480*34114Skarels } 481*34114Skarels while ((ct->catcode < curcode) && (ct <= &ctab[nchars])) { 482*34114Skarels ct++; 483*34114Skarels i++; 484*34114Skarels } 485*34114Skarels if (ct >= &ctab[nchars]) break; 486*34114Skarels map.wid = ct->wid; 487*34114Skarels map.pswidth = ct->pswidth; 488*34114Skarels map.x = ct->x; 489*34114Skarels map.y = ct->y; 490*34114Skarels map.action = ct->action; 491*34114Skarels map.pschar = ct->pschar; 492*34114Skarels map.font = ct->font; 493*34114Skarels VOIDC write(fileno(mapfile), &map, sizeof map); 494*34114Skarels ct++; 495*34114Skarels curcode++; 496*34114Skarels } 497*34114Skarels VOIDC fclose(mapfile); 498*34114Skarels } 499*34114Skarels 500*34114Skarels 501*34114Skarels /* called by qsort to compare troff codes */ 502*34114Skarels /* if troff codes are the same, use facecode to decide */ 503*34114Skarels 504*34114Skarels private compTRcode(a,b)struct ctab *a, *b; 505*34114Skarels { 506*34114Skarels register int i; 507*34114Skarels i = a->trcode - b->trcode; 508*34114Skarels if (i == 0) return ((a->catcode>>7) - (b->catcode>>7)); 509*34114Skarels return(i); 510*34114Skarels } 511*34114Skarels 512*34114Skarels 513*34114Skarels private DoWidths() { 514*34114Skarels int f; /* font index 0-3 */ 515*34114Skarels 516*34114Skarels qsort((char *) ctab, nchars, sizeof(struct ctab), compTRcode); 517*34114Skarels for (f = 0; f < 4; f++) { 518*34114Skarels dofont(f); 519*34114Skarels } 520*34114Skarels } 521*34114Skarels 522*34114Skarels 523*34114Skarels #define ASCENDER 0200 524*34114Skarels #define DESCENDER 0100 525*34114Skarels 526*34114Skarels /* note that both is 0300 */ 527*34114Skarels /* ascenders are: 528*34114Skarels * b d f h i j k l t beta gamma delta zeta theta lambda xi 529*34114Skarels * phi psi Gamma Delta Theta Lambda Xi Pi Sigma 530*34114Skarels * Upsilon Phi Psi Omega gradient 531*34114Skarels */ 532*34114Skarels 533*34114Skarels private char Ascenders[] = "bdfhijklt\231\232\233\235\237\242\245\254\256\260\261\262\263\264\264\265\266\270\271\272\273\326"; 534*34114Skarels 535*34114Skarels /* descenders are: 536*34114Skarels * g j p q y beta zeta eta mu xi 537*34114Skarels * rho phi chi psi terminal-sigma 538*34114Skarels */ 539*34114Skarels 540*34114Skarels private char Descenders[] = "gjpqy\231\235\236\243\245\250\254\255\256\275"; 541*34114Skarels 542*34114Skarels 543*34114Skarels private dofont(fontno) 544*34114Skarels int fontno; /* troff font number 0-3 */ 545*34114Skarels { 546*34114Skarels char ftfilename[100]; 547*34114Skarels FILE *ftfile; /* generated font widths file */ 548*34114Skarels int wid, curcode; 549*34114Skarels struct ctab *ct, *cc; 550*34114Skarels int asde; 551*34114Skarels 552*34114Skarels #ifdef SYSV 553*34114Skarels VOIDC sprintf(ftfilename, "ft%s", facenames[fontno]); 554*34114Skarels #else 555*34114Skarels VOIDC sprintf(ftfilename, "ft%s.c", facenames[fontno]); 556*34114Skarels #endif 557*34114Skarels if ((ftfile = fopen(ftfilename, "w")) == NULL) { 558*34114Skarels perror(ftfilename); 559*34114Skarels exit(1); 560*34114Skarels } 561*34114Skarels #ifdef BSD 562*34114Skarels fprintf(ftfile, "/* troff width file for %s - %s (%c) */\n", 563*34114Skarels familyname, facenames[fontno], faces[fontno]); 564*34114Skarels fprintf(ftfile, "char ft%s[256-32] = {\n", facenames[fontno]); 565*34114Skarels #endif 566*34114Skarels 567*34114Skarels /* write out entry for each troff character code */ 568*34114Skarels /* codes 0-31 (decimal) are not used */ 569*34114Skarels /* the first interesting code is 32 (040) - space */ 570*34114Skarels 571*34114Skarels ct = ctab; 572*34114Skarels for (curcode = 32; curcode < 256; curcode++) { 573*34114Skarels while ((ct < &ctab[nchars]) && (ct->trcode < curcode) || 574*34114Skarels ((ct->trcode == curcode) && ((ct->catcode>>7) < fontno))) { 575*34114Skarels ct++; 576*34114Skarels } 577*34114Skarels asde = 0; 578*34114Skarels if ((ct >= &ctab[nchars]) || (curcode != ct->trcode) || 579*34114Skarels ((ct->catcode>>7) != fontno)) { 580*34114Skarels /* not found */ 581*34114Skarels wid = 0; 582*34114Skarels cc = 0; 583*34114Skarels } 584*34114Skarels else { 585*34114Skarels wid = ct->wid; 586*34114Skarels cc = ct; 587*34114Skarels /* calculate ascender/descender info (heuristic) */ 588*34114Skarels if (((curcode >= '0') && (curcode <= '9')) || 589*34114Skarels ((curcode >= 'A') && (curcode <= 'Z'))) asde |= ASCENDER; 590*34114Skarels if (INDEX(Ascenders, curcode)) asde |= ASCENDER; 591*34114Skarels if (INDEX(Descenders, curcode)) asde |= DESCENDER; 592*34114Skarels } 593*34114Skarels #ifdef SYSV 594*34114Skarels /* for system V we write a binary file of the width bytes */ 595*34114Skarels putc(0377&(wid+asde),ftfile); 596*34114Skarels #else 597*34114Skarels /* for BSD we write a "c" array to be compiled */ 598*34114Skarels fprintf(ftfile, "%d", wid); 599*34114Skarels if (asde) fprintf(ftfile,"+0%o",asde); 600*34114Skarels fprintf(ftfile, ",\t%s/* %s */\n", 601*34114Skarels asde?"":"\t",cc?cc->descr:"NULL"); 602*34114Skarels #endif 603*34114Skarels } 604*34114Skarels #ifdef BSD 605*34114Skarels fprintf(ftfile,"};\n"); 606*34114Skarels #endif 607*34114Skarels VOIDC fclose(ftfile); 608*34114Skarels } 609*34114Skarels 610*34114Skarels 611*34114Skarels main(argc, argv) 612*34114Skarels int argc; 613*34114Skarels char **argv; 614*34114Skarels { 615*34114Skarels if (argc != 2) { 616*34114Skarels fprintf(stderr,"usage: pscatmap mapfile\n"); 617*34114Skarels exit(1); 618*34114Skarels } 619*34114Skarels if (freopen(*++argv,"r",stdin) == NULL) { 620*34114Skarels perror("pscatmap"); 621*34114Skarels exit(1); 622*34114Skarels } 623*34114Skarels 624*34114Skarels if ((libdir = envget("PSLIBDIR")) == NULL) libdir = LibDir; 625*34114Skarels 626*34114Skarels BuildTable(); 627*34114Skarels WriteTable(); 628*34114Skarels DoWidths(); 629*34114Skarels } 630*34114Skarels 631