home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / ltroff / part02 / tlc.c < prev   
Encoding:
C/C++ Source or Header  |  1993-07-15  |  35.4 KB  |  1,788 lines

  1. #include "ansic.h"
  2. ID(elsieid, "@(#)tlc.c    4.1")
  3.  
  4. extern int        getopt();
  5. extern char *        optarg;
  6. extern int        optind;
  7.  
  8. #ifndef BUFSIZ
  9. #define BUFSIZ        1024
  10. #endif /* !defined BUFSIZ */
  11.  
  12. #ifndef MAXFILES
  13. #define MAXFILES    20
  14. #endif /* !defined MAXFILES */
  15.  
  16. #ifndef NVPC
  17. #define NVPC        256
  18. #endif /* !defined NVPC */
  19.  
  20. #ifndef TRUE
  21. #define TRUE        1
  22. #define FALSE        0
  23. #endif /* !defined TRUE */
  24.  
  25. #define NPPI        72    /* Number of Points Per Inch */
  26. #define NCHUPI        432    /* Number of C/A/T Horizontal Units Per Inch */
  27. #define NCVUPI        144    /* Number of C/A/T Vertical Units Per Inch */
  28. #define NCWUPI        NCHUPI    /* Number of C/A/T Width table Units Per Inch */
  29. #define CWPS        6    /* C/A/T Width Value Point Size */
  30. #define DNIPP        11    /* Default Number of Inches Per Page */
  31. #define NI        256    /* Number of troff width table indices */
  32. #define MAXPS        36    /* Maxium Point Size */
  33.  
  34. static struct {
  35.     const char *    f_fontnick;
  36.     char *        f_in;        /* how to get into font */
  37.     char *        f_out;        /* how to get out of font */
  38. } fontdata[] = {
  39.     { "R" },
  40.     { "I" },
  41.     { "B" },
  42.     { "S" }
  43. };
  44.  
  45. #define NFONTS    (sizeof fontdata / sizeof fontdata[0])
  46.  
  47. #define fontisx(font, x) (fontdata[font].f_fontnick[0] == (x))
  48. #define fontisR(font) (fontisx(font, 'R'))
  49. #define fontisI(font) (fontisx(font, 'I'))
  50. #define fontisB(font) (fontisx(font, 'B'))
  51. #define fontisS(font) (fontisx(font, 'S'))
  52.  
  53. /* Number of C/A/T Vertical Units Per Page */
  54.  
  55. static int        ncvupp = NCVUPI * DNIPP;
  56.  
  57. static float        lwupi;        /* laser width units per inch */
  58. static float        lwps;        /* laser width point size */
  59. static float        lcpi;        /* laser characters per inch */
  60.  
  61. static char *        sizes;        /* how to get into/out of sizes */
  62.  
  63. static char *        firsts[MAXPS + 1][NFONTS];
  64.                     /* for first time font and size seen */
  65.  
  66. static int        lowvalue;
  67.  
  68. static char *        lowstring;
  69.  
  70. static char *        hormove;    /* horizontal move format */
  71. static char *        vermove;    /* vertical move format */
  72. static char *        enddata;    /* data to send when done */
  73. static char *        newpage;    /* data to send for new page */
  74. static char *        portrait;    /* to go into portrait mode */
  75. static char *        landscape;    /* to go into landscape mode */
  76.  
  77. static int        verunitsperinch;/* printer vertical units per inch */
  78.  
  79. static int        horunitsperinch;/* printer horizontal units per inch */
  80.  
  81. static int        leftmargin;    /* unprintable left margin */
  82.  
  83. /*
  84. ** Per-"character" data.
  85. */
  86.  
  87. typedef struct {
  88.     char *    ssname;            /* symbol set name */
  89.     char *    inset;            /* how to get into symbol set */
  90.     char *    outset;            /* how to get out of symbol set */
  91.     char *    data;            /* character-specific data */
  92.     int    widths[NFONTS];        /* widths in various fonts */
  93.     int    lwidths[NFONTS];    /* LJ widths */
  94.     char    waschar;        /* explicitly-set character */
  95. } item;
  96.  
  97. static item        items[2 * NI];
  98.  
  99. static int        overstruck[NI];
  100.  
  101. static unsigned char *    overnames[2 * NI];
  102.  
  103. /*
  104. ** Internal functions.
  105. */
  106.  
  107. static void        LJ_cput();
  108. static void        LJ_fdput();
  109. static void        LJ_sput();
  110. static int        ascends();
  111. static char *        checkcp();
  112. static void *        checkvp();
  113. static int        ctoi();
  114. static int        descends();
  115. static FILE *        dfopen();
  116. static void        disescape();
  117. static void        dostrike();
  118. static void        dowidth();
  119. static char *        ecatalloc();
  120. static char *        ecpyalloc();
  121. static void *        emalloc();
  122. static int        fiswidth();
  123. static char *        getline();
  124. static char *        icatalloc();
  125. static char *        icpyalloc();
  126. static void        ifree();
  127. static void *        imalloc();
  128. static int        inch();
  129. static void *        irealloc();
  130. static int        linematch();
  131. static void        loadinfo();
  132. static void        loadsub();
  133. static int        lwtocw();
  134. int            main();
  135. static const char *    namefor();
  136. static int        nametoindex();
  137. static int        oscode();
  138. static int        osfind();
  139. static int        ouch();
  140. static const char *    scheck();
  141. static int        splitos();
  142. static void        swift();
  143. static void        tameexit();
  144. static void        wild2();
  145. static void        wild2exit();
  146. static void        wildexit();
  147. static void        wildline();
  148. static void        wildrexit();
  149.  
  150. /*
  151. ** External functions.
  152. */
  153.  
  154. extern int        catsup();
  155. extern const char *    fti2ntn();
  156. extern int        ntn2fti();
  157. extern int        ntnonr();
  158. extern int        ntnons();
  159.  
  160. /*
  161. ** Messages and exits.
  162. */
  163.  
  164. static const char *    progname;
  165.  
  166. static void
  167. wild2(part1, part2)
  168. const char * const    part1;
  169. const char * const    part2;
  170. {
  171.     (void) fflush(stdout);
  172.     /*
  173.     ** One space after the colon matches what perror does
  174.     ** (although your typing teacher may want a second space).
  175.     */
  176.     (void) fprintf(stderr, "\n%s: wild", progname);
  177.     if (part1 != NULL && *part1 != '\0')
  178.         (void) fprintf(stderr, " %s", part1);
  179.     if (part2 != NULL && *part2 != '\0')
  180.         (void) fprintf(stderr, " %s", part2);
  181.     (void) fprintf(stderr, "\n");
  182. }
  183.  
  184. static void
  185. wild2exit(string1, string2)
  186. const char * const    string1;
  187. const char * const    string2;
  188. {
  189.     wild2(string1, string2);
  190.     exit(EXIT_FAILURE);
  191.     /*NOTREACHED*/
  192. }
  193.  
  194. static void
  195. wildexit(string)
  196. const char * const    string;
  197. {
  198.     wild2exit(string, (char *) NULL);
  199.     /*NOTREACHED*/
  200. }
  201.  
  202. static void
  203. wildrexit(string)
  204. const char * const    string;
  205. {
  206.     wild2exit("result from", string);
  207.     /*NOTREACHED*/
  208. }
  209.  
  210. static void
  211. tameexit()
  212. {
  213.     exit(EXIT_SUCCESS);
  214.     /*NOTREACHED*/
  215. }
  216.  
  217. /*
  218. ** Memory allocation.
  219. */
  220.  
  221. #ifndef alloc_size_t
  222. #define alloc_size_t    unsigned
  223. #endif /* !defined alloc_size_t */
  224.  
  225. #ifndef alloc_pointer_t
  226. #define alloc_pointer_t char *
  227. #endif /* !defined alloc_pointer_t */
  228.  
  229. #ifdef MAL
  230. #define NULLMAL(x)    ((x) == NULL || (x) == MAL)
  231. #else /* !defined MAL */
  232. #define NULLMAL(x)    ((x) == NULL)
  233. #endif /* !defined MAL */
  234.  
  235. #define nonzero(n)    (((n) == 0) ? 1 : (n))
  236.  
  237. static void *
  238. imalloc(n)
  239. int const    n;
  240. {
  241. #ifdef MAL
  242.     char *    result;
  243.  
  244.     result = (void *) malloc((alloc_size_t) nonzero(n));
  245.     return NULLMAL(result) ? NULL : result;
  246. #else /* !defined MAL */
  247.     return (void *) malloc((alloc_size_t) nonzero(n));
  248. #endif /* !defined MAL */
  249. }
  250.  
  251. static void *
  252. irealloc(pointer, size)
  253. void * const    pointer;
  254. int const    size;
  255. {
  256.     if (NULLMAL(pointer))
  257.         return imalloc(size);
  258.     return (void *) realloc((alloc_pointer_t) pointer,
  259.         (alloc_size_t) nonzero(size));
  260. }
  261.  
  262. static char *
  263. icatalloc(old, new)
  264. char * const        old;
  265. const char * const    new;
  266. {
  267.     char *    result;
  268.     int    oldsize;
  269.     int    newsize;
  270.  
  271.     newsize = NULLMAL(new) ? 0 : strlen(new);
  272.     if (NULLMAL(old))
  273.         oldsize = 0;
  274.     else if (newsize == 0)
  275.         return old;
  276.     else    oldsize = strlen(old);
  277.     result = (char *) irealloc((void *) old, oldsize + newsize + 1);
  278.     if (result != NULL)
  279.         if (NULLMAL(new))
  280.             *(result + oldsize) = '\0';
  281.         else    (void) strcpy(result + oldsize, new);
  282.     return result;
  283. }
  284.  
  285. static char *
  286. icpyalloc(string)
  287. const char * const    string;
  288. {
  289.     return icatalloc((char *) NULL, string);
  290. }
  291.  
  292. static void
  293. ifree(p)
  294. void * const    p;
  295. {
  296.     if (!NULLMAL(p))
  297. #ifdef USG
  298.         free((alloc_pointer_t) p);
  299. #endif /* defined USG */
  300. #ifndef USG
  301.         (void) free((alloc_pointer_t) p);
  302. #endif /* !defined USG */
  303. }
  304.  
  305. static void *
  306. checkvp(pointer)
  307. void * const    pointer;
  308. {
  309.     if (pointer == NULL)
  310.         wildrexit("allocating memory");
  311.     return pointer;
  312. }
  313.  
  314. static char *
  315. checkcp(pointer)
  316. char * const    pointer;
  317. {
  318.     if (pointer == NULL)
  319.         wildrexit("allocating memory");
  320.     return pointer;
  321. }
  322.  
  323. static void *
  324. emalloc(size)
  325. int const    size;
  326. {
  327.     return checkvp(imalloc(size));
  328. }
  329.  
  330. static char *
  331. ecatalloc(old, new)
  332. char * const        old;
  333. const char * const    new;
  334. {
  335.     return checkcp(icatalloc(old, new));
  336. }
  337.  
  338. static char *
  339. ecpyalloc(string)
  340. const char * const    string;
  341. {
  342.     return checkcp(icpyalloc(string));
  343. }
  344.  
  345. /*
  346. ** Check a format against a string...
  347. */
  348.  
  349. static const char *
  350. scheck(string, format)
  351. const char * const    string;
  352. const char * const    format;
  353. {
  354.     char *        fbuf;
  355.     const char *    fp;
  356.     char *        tp;
  357.     int        c;
  358.     const char *    result;
  359.     char            dummy;
  360.  
  361.     result = "";
  362.     if (string == NULL || format == NULL)
  363.         return result;
  364.     /*
  365.     ** Check for stupid systems that let "9e" match "%f".
  366.     ** We only do the easy cases here.
  367.     */
  368.     {
  369.         int    i;
  370.  
  371.         i = strlen(format);
  372.         if (i >= 2 && strcmp(&format[i - 2], "%f") == 0) {
  373.             i = strlen(string);
  374.             if (i > 0 &&
  375.                 strchr("0123456789", string[i - 1]) == NULL)
  376.                     return result;
  377.         }
  378.     }
  379.     fbuf = (char *) imalloc(2 * strlen(format) + 4);
  380.     if (fbuf == NULL)
  381.         return result;
  382.     fp = format;
  383.     tp = fbuf;
  384.     while ((*tp++ = c = *fp++) != '\0') {
  385.         if (c != '%')
  386.             continue;
  387.         if (*fp == '%') {
  388.             *tp++ = *fp++;
  389.             continue;
  390.         }
  391.         *tp++ = '*';
  392.         if (*fp == '*')
  393.             ++fp;
  394.         while (isascii(*fp) && isdigit(*fp))
  395.             *tp++ = *fp++;
  396.         if (*fp == 'l' || *fp == 'h')
  397.             *tp++ = *fp++;
  398.         else if (*fp == '[')
  399.             do {
  400.                 *tp++ = *fp++;
  401.             } while (*fp != '\0' && *fp != ']');
  402.         if ((*tp++ = *fp++) == '\0')
  403.             break;
  404.     }
  405.     *(tp - 1) = '%';
  406.     *tp++ = 'c';
  407.     *tp = '\0';
  408.     if (sscanf(string, fbuf, &dummy) != 1)
  409.         result = format;
  410.     ifree((void *) fbuf);
  411.     return result;
  412. }
  413.  
  414. /*
  415. ** Get [nt]roff names from a file.
  416. */
  417.  
  418. static const char *    sfilename;
  419. static int        slinenum;
  420.  
  421. static void
  422. oops(string)
  423. const char * const    string;
  424. {
  425.     char    line[132];
  426.  
  427.     (void) sprintf(line, "file \"%s\", line %d: %s\n",
  428.         ((sfilename == NULL) ? NULL : sfilename), slinenum, string);
  429.     wildexit(line);
  430. }
  431.  
  432. static void
  433. getnames(filename, names)
  434. const char * const    filename;
  435. char ** const        names;
  436. {
  437.     FILE *    fp;
  438.     char *    cp;
  439.     char *    dp;
  440.     int    i;
  441.     int    online;
  442.     char        line[132];
  443.  
  444.     sfilename = filename;
  445.     slinenum = 0;
  446.     if (names == NULL)
  447.         oops("NULL names argument");
  448.     if (filename == NULL)
  449.         oops("NULL filename argument");
  450.     if ((fp = fopen(filename, "r")) == NULL) {
  451.         cp = ecpyalloc(filename);
  452.         cp = ecatalloc(cp, ".M");
  453.         fp = fopen(cp, "r");
  454.         free(cp);
  455.         if (fp == NULL)
  456.             oops("can't open file");
  457.     }
  458.     i = 0;
  459.     while (fgets(line, sizeof line, fp) == line) {
  460.         ++slinenum;
  461.         if ((cp = strchr(line, '\n')) == NULL)
  462.             oops("line is too long");
  463.         *cp = '\t';    /* means all fields are tab terminated */
  464.         for (cp = line; *cp != '\0'; ++cp)
  465.             if (!isascii(*cp))
  466.                 oops("non-ASCII character in line");
  467.         cp = line;
  468.         if (*cp == '#' || *cp == '\0')
  469.             continue;
  470.         if (i >= NVPC)
  471.             oops("too many lines in input");
  472.         if (!isspace(*cp))
  473.             oops("data line does not begin with space");
  474.         for (online = 0; online < 8; ++online) {
  475.             while (*cp != '\0' && isspace(*cp))
  476.                 ++cp;
  477.             dp = cp;
  478.             while (*dp != '\0' && !isspace(*dp))
  479.                 ++dp;
  480.             if (dp == NULL)
  481.                 oops("too few fields on line");
  482.             *dp = '\0';
  483.             names[i++] = (strcmp(cp, "NULL") == 0) ? NULL :
  484.                 ecpyalloc(cp);
  485.             cp = dp + 1;
  486.         }
  487.         while (isspace(*cp))
  488.             ++cp;
  489.         if (*cp != '\0')
  490.             oops("wrong number of fields on line");
  491.     }
  492.     if (!feof(fp) || ferror(fp))
  493.         oops("wild result reading file");
  494.     if (fclose(fp)) {
  495.         fp = NULL;
  496.         oops("wild result closing file");
  497.     }
  498.     for ( ; i < NVPC; ++i)
  499.         names[i] = NULL;
  500. }
  501.  
  502. /*
  503. ** And now the real work begins...
  504. */
  505.  
  506. static int
  507. fiswidth(font, fti, size)
  508. int const    font;
  509. int const    fti;
  510. int const    size;
  511. {
  512.     int    w;
  513.     int    result;
  514.  
  515.     w = items[fti].widths[font];
  516.     result = w * size / CWPS;
  517.     if (((w * size) % CWPS) >= (CWPS / 2))
  518.         ++result;
  519.     return result;
  520. }
  521.  
  522. static int        vflag;
  523. static int        wflag;
  524. static int        xynh;
  525.  
  526. static int
  527. inch()
  528. {
  529.     return getchar();
  530. }
  531.  
  532. typedef struct {
  533.     int    fti;
  534.     long    hor;
  535.     long    ver;
  536.     int    font;
  537.     int    size;
  538. } strike;
  539.  
  540. static int
  541. osfind(a, b)
  542. int const    a;
  543. int const    b;
  544. {
  545.     unsigned char *    ucp;
  546.     int            i;
  547.  
  548.     for (i = NI; ; ++i) {
  549.         ucp = (unsigned char *) overnames[i];
  550.         if (ucp == NULL || *ucp == '\0')
  551.             return 0;
  552.         if (*ucp == a && *(ucp + 1) == b)
  553.             return i;
  554.         if (*ucp == b && *(ucp + 1) == a)
  555.             return i;
  556.     }
  557. }
  558.  
  559. static int
  560. oscode(one, two)
  561. strike    one;
  562. strike    two;
  563. {
  564.     strike    three;    /* You're out! */
  565.  
  566.     if (one.ver != two.ver || one.size != two.size)
  567.         return 0;
  568.     if (one.font != two.font && !fontisS(one.font) && !fontisS(two.font))
  569.         return 0;
  570.     if (!overstruck[one.fti] || !overstruck[two.fti])
  571.         return 0;
  572.     if (one.fti == two.fti && one.hor != two.hor)
  573.         return 0;
  574.     if (one.hor > two.hor) {
  575.         three = one;
  576.         one = two;
  577.         two = three;
  578.     }
  579.     if ((two.hor - one.hor) >= fiswidth(one.font, one.fti, one.size) / 2)
  580.         return 0;
  581.     return osfind(one.fti, two.fti);
  582. }
  583.  
  584. static int
  585. ouch(charname, wchor, wcver, wsize, fontnick)
  586. const char * const    charname;
  587. long const        wchor;    /* wanted C/A/T horizontal position */
  588. long            wcver;    /* wanted C/A/T veritcal position */
  589. int const        wsize;
  590. char * const        fontnick;
  591. {
  592.     int    wfont;
  593.     int    fti;
  594.     int    i;
  595.     strike        s;
  596.     static strike    ss = { 0, -1, -1, -1, -1 };
  597.  
  598.     fti = ntn2fti(charname);
  599.     wcver -= 31;
  600.     s.fti = fti;
  601.     s.hor = wchor;
  602.     s.ver = wcver;
  603.     for (wfont = 0; ; ++wfont) {
  604.         if (wfont == NFONTS)
  605.             wild2exit("font -", fontnick);
  606.         if (strcmp(fontnick, fontdata[wfont].f_fontnick) == 0)
  607.             break;
  608.     }
  609.     s.font = wfont;
  610.     s.size = wsize;
  611.     if ((i = oscode(s, ss)) > 0) {
  612.         if (s.hor > ss.hor)
  613.             s.hor = ss.hor;
  614.         if (fontisS(s.font))
  615.             s.font = ss.font;
  616.         s.fti = i;
  617.         dostrike(s);
  618.         ss.fti = 0;
  619.     } else {
  620.         if (ss.ver != s.ver ||
  621.             (s.hor - ss.hor) >=
  622.             fiswidth(ss.font, ss.fti, ss.size) / 2) {
  623.                 dostrike(ss);
  624.                 ss.fti = 0;
  625.         }
  626.         if (!overstruck[fti]) {
  627.             dostrike(s);
  628.         } else {
  629.             dostrike(ss);
  630.             ss = s;
  631.         }
  632.     }
  633.     return 0;
  634. }
  635.  
  636. static const char *    cartridge;
  637.  
  638. int
  639. main(argc, argv)
  640. int    argc;
  641. char *    argv[];
  642. {
  643.     int    c;
  644.     int    nargs;
  645.  
  646.     if ((progname = strrchr(argv[0], '/')) == NULL)
  647.         progname = argv[0];
  648.     else    ++progname;
  649.     while ((c = getopt(argc, argv, "vwx:y:n:h:")) != EOF)
  650.         if (c == 'x' || c == 'y' || c == 'n' || c == 'h')
  651.             xynh = TRUE;
  652.         else if (c == 'v')
  653.             vflag = TRUE;
  654.         else if (c == 'w')
  655.             wflag = TRUE;
  656.         else    break;
  657.     nargs = argc - optind;
  658.     if (c != EOF ||
  659.         (vflag && !wflag) ||
  660.         nargs != (xynh ? 0 : 1) ||
  661.         (nargs == 1 && strcmp(argv[optind], "=") == 0)) {
  662.         (void) fprintf(stderr,
  663.             "%s: usage is %s [-wv] fontdir < file\n",
  664.             progname, progname);
  665.         if (nargs == 1 && strcmp(argv[optind], "=") == 0)
  666.             tameexit();
  667.         else    wildexit("usage");
  668.     }
  669.     if (!wflag)
  670.         if ((c = getchar()) == EOF)
  671.             tameexit();
  672.         else    (void) ungetc(c, stdin);
  673.     if (nargs == 1)
  674.         cartridge = argv[optind];
  675.     else {
  676.         FILE *    fp;
  677.         char *    cp;
  678.         static char    buf[132];
  679.  
  680.         fp = fopen(".railmag", "r");
  681.         if (fp == NULL)
  682.             wildrexit("opening .railmag");
  683.         if (fgets(buf, sizeof buf, fp) != buf)
  684.             wildrexit("reading .railmag");
  685.         if (strchr(buf, '\n') == NULL)
  686.             wildexit("missing newline in .railmag");
  687.         if ((cp = strrchr(buf, '/')) == NULL)
  688.             wildexit("missing / in .railmag");
  689.         if (fclose(fp))
  690.             wildrexit("closing .railmag");
  691.         *cp = '\0';
  692.         /*
  693.         ** Horrid special case.
  694.         ** Maybe should check that directory exists.
  695.         */
  696.         if (strcmp(buf, "/usr/lib/vfont") == 0) {
  697.             (void) strcpy(buf, DATADIR);
  698.             (void) strcat(buf, "/default");
  699.         }
  700.         cartridge = buf;
  701.     }
  702.     loadinfo();
  703.     if (wflag) {
  704.         dowidth();
  705.         tameexit();
  706.     }
  707.     if (catsup(inch, ouch, TRUE, FALSE) != 0)
  708.         wildrexit("catsup");
  709.     (void) ouch("", 0L, 0L, 0, "R");    /* to flush */
  710.     if (!feof(stdin) || ferror(stdin))
  711.         wildrexit("reading standard input");
  712.     LJ_sput(enddata);
  713.     if (ferror(stdout))
  714.         wildrexit("writing");
  715.     return 0;
  716. }
  717.  
  718. /*
  719. ** Convert laser width table units to C/A/T width table units
  720. */
  721.  
  722. static int
  723. lwtocw(fti, font, lw)
  724. int const    fti;
  725. int const    font;
  726. int const    lw;
  727. {
  728.     int    cw;
  729.     long    num;
  730.     long    den;
  731.     static int    prevind;
  732.  
  733.     num = (long) lw * NCWUPI * CWPS;
  734.     den = lwupi * lwps;
  735.     cw = num / den;
  736.     /*
  737.     ** Selectively round to ensure that rules meet.
  738.     */
  739.     if (isascii(fti) && isprint(fti) && fti != '_')
  740.         if ((num % den) >= (den / 2))
  741.             ++cw;
  742.     if (cw > 077) {
  743.         if (wflag && fti != prevind) {
  744.             (void) fprintf(stderr,
  745. "%s: note: char %s, font %s in %s too wide (%d, %d)\n",
  746.                 progname, fti2ntn(fti),
  747.                 fontdata[font].f_fontnick, cartridge, lw, cw);
  748.             prevind = fti;
  749.         }
  750.         cw = 077;
  751.     }
  752.     return cw;
  753. }
  754.  
  755. static char *    filenames[MAXFILES];
  756. static long    linenums[MAXFILES];
  757. static int    lastfid;
  758.  
  759. static void
  760. wildline(message)
  761. const char * const    message;
  762. {
  763.     char *    filename;
  764.     long    linenum;
  765.  
  766.     if (lastfid >= 0 && lastfid < MAXFILES) {
  767.         filename = filenames[lastfid];
  768.         linenum = linenums[lastfid];
  769.     } else {
  770.         filename = NULL;
  771.         linenum = -1;
  772.     }
  773.     (void) fprintf(stderr, "%s: ", progname);
  774.     if (filename == NULL)
  775.         (void) fprintf(stderr, "file UNKNOWN, ");
  776.     else    (void) fprintf(stderr, "file \"%s\", ", filename);
  777.     (void) fprintf(stderr, "line %ld: ", linenum);
  778.     (void) fprintf(stderr, "wild %s\n",
  779.         ((message == NULL) ? "line" : message));
  780.     wildexit("information file");
  781. }
  782.  
  783. static int
  784. ctoi(c)
  785. int const    c;
  786. {
  787.     const char *    cp;
  788.     static const char    digits[] = "0123456789";
  789.  
  790.     cp = strchr(digits, c);
  791.     return (cp == NULL) ? -1 : (cp - digits);
  792. }
  793.  
  794. static void
  795. disescape(cp)
  796. char * const    cp;
  797. {
  798.     const char *    fromp;
  799.     char *        top;
  800.     int        c;
  801.     int        i;
  802.     int        j;
  803.  
  804.     fromp = top = cp;
  805.     while ((c = *fromp++) != '\0')
  806.         if (c != '\\')
  807.             *top++ = c;
  808.         else switch ((c = *fromp++)) {
  809.             case '\0':    --fromp; *top++ = '\\';    break;
  810.             case 'E':    *top++ = '\033';    break;
  811.             case 'b':    *top++ = '\b';        break;
  812.             case 'f':    *top++ = '\f';        break;
  813.             case 'n':    *top++ = '\n';        break;
  814.             case 'r':    *top++ = '\r';        break;
  815.             case 't':    *top++ = '\t';        break;
  816.             case 'v':    *top++ = '\v';        break;
  817.             default:
  818.                 i = ctoi(c);
  819.                 if (i < 0 || i > 7) {
  820.                     *top++ = c;
  821.                     break;
  822.                 }
  823.                 if ((j = ctoi(*fromp)) >= 0 && j <= 7) {
  824.                     ++fromp;
  825.                     i = i * 8 + j;
  826.                     if ((j = ctoi(*fromp)) >= 0 && j <= 7) {
  827.                         ++fromp;
  828.                         i = i * 8 + j;
  829.                     }
  830.                 }
  831.                 *top++ = i;
  832.                 break;
  833.         }
  834.     *top = '\0';
  835. }
  836.  
  837. static FILE *
  838. dfopen(filename, mode, must)
  839. const char * const    filename;
  840. const char * const    mode;
  841. int const        must;
  842. {
  843.     FILE *    fp;
  844.     char *    cp;
  845.     char *    dp;
  846.     int    fid;
  847.     int    pass;
  848.  
  849.     dp = ecpyalloc(cartridge);
  850.     for (pass = 1; pass <= 2; ++pass) {
  851.         if (pass == 2)
  852.             if ((cp = strrchr(dp, '/')) == NULL)
  853.                 (void) strcpy(dp, ".");
  854.             else    *cp = '\0';
  855.         cp = ecpyalloc(dp);
  856.         cp = ecatalloc(cp, "/");
  857.         cp = ecatalloc(cp, filename);
  858.         fp = fopen(cp, mode);
  859.         if (fp == NULL) {
  860.             free(cp);
  861.             continue;
  862.         }
  863.         fid = fileno(fp);
  864.         if (fid < 0)
  865.             wildexit("negative file descriptor!?");
  866.         if (fid >= MAXFILES)
  867.             wildexit("large number of files opened");
  868.         if (filenames[fid] != NULL)
  869.             free(filenames[fid]);
  870.         filenames[fid] = cp;
  871.         linenums[fid] = 0;
  872.         free(dp);
  873.         return fp;
  874.     }
  875.     free(dp);
  876.     if (must)
  877.         wild2exit("result opening file", filename);
  878.     return NULL;
  879. }
  880.  
  881. static const char *
  882. namefor(fp)
  883. FILE * const    fp;
  884. {
  885.     int            fid;
  886.     static const char    unknown[] = "UNKNOWN";
  887.  
  888.     if (fp != NULL) {
  889.         fid = fileno(fp);
  890.         if (fid >= 0 && fid < MAXFILES && filenames[fid] != NULL)
  891.             return filenames[fid];
  892.     }
  893.     return unknown;
  894. }
  895.  
  896. static char *
  897. getline(fp)
  898. FILE * const    fp;
  899. {
  900.     char *    cp;
  901.     char *    dp;
  902.     static char    line[BUFSIZ];
  903.  
  904.     lastfid = fileno(fp);
  905.     for ( ; ; ) {
  906.         if (fgets(line, sizeof line, fp) != line) {
  907.             if (ferror(fp) || !feof(fp))
  908.                 wildline("result from reading");
  909.             if (fclose(fp))
  910.                 wildline("result from closing");
  911.             return NULL;
  912.         }
  913.         ++linenums[(int) fileno(fp)];
  914.         cp = strchr(line, '\n');
  915.         if (cp == NULL)
  916.             wildline("long line");
  917.         *cp = '\0';
  918.         /*
  919.         ** Strip comments and trailing space.
  920.         */
  921.         dp = NULL;
  922.         for (cp = line; *cp != '\0'; ++cp)
  923.             if (*cp == '#') {
  924.                 *cp = '\0';
  925.                 break;
  926.             } else if (isascii(*cp) && isspace(*cp)) {
  927.                 if (dp == NULL)
  928.                     dp = cp;
  929.             } else {
  930.                 dp = NULL;
  931.                 if (*cp == '\\') {
  932.                     if (*++cp == '\0')
  933.                         break;
  934.                 }
  935.             }
  936.         if (dp != NULL)
  937.             *dp = '\0';
  938.         /*
  939.         ** If we've got something. . .
  940.         */
  941.         if (line[0] != '\0')
  942.             return line;
  943.     }
  944. }
  945.  
  946. static int
  947. splitos(name, vals)
  948. char * const    name;
  949. int        vals[2];
  950. {
  951.     char *    cp;
  952.     int    left;
  953.     int    right;
  954.     int    n;
  955.     int    c;
  956.  
  957.     if (name == NULL || *name == '\0')
  958.         return -1;
  959.     n = 0;
  960.     for (cp = name + 1; *cp != '\0'; ++cp) {
  961.         if ((right = ntn2fti(cp)) <= 0)
  962.             continue;
  963.         c = *cp;
  964.         *cp = '\0';
  965.         left = ntn2fti(name);
  966.         *cp = c;
  967.         if (left <= 0)
  968.             continue;
  969.         if (++n > 1)
  970.             return -1;
  971.         vals[0] = left;
  972.         vals[1] = right;
  973.     }
  974.     return (n == 1) ? 0 : -1;
  975. }
  976.  
  977. static int
  978. nametoindex(name)
  979. const char * const    name;
  980. {
  981.     int        fti;
  982.     int        vals[2];
  983.     static int    oi = NI;
  984.  
  985.     if ((fti = ntn2fti(name)) > 0)
  986.         return fti;
  987.     /*
  988.     ** Overstrike mapping?
  989.     */
  990.     if (splitos(name, vals) != 0) {
  991.         char    minibuf[132];
  992.  
  993.         (void) sprintf(minibuf, "character name--\"%s\"", name);
  994.         wildline(minibuf);
  995.     }
  996.     if ((fti = osfind(vals[0], vals[1])) > 0)
  997.         return fti;
  998.     if (oi >= sizeof items / sizeof items[0])
  999.         wildline("large number of overstrikes");
  1000.     overstruck[vals[0]] = TRUE;
  1001.     overstruck[vals[1]] = TRUE;
  1002.     overnames[oi] = (unsigned char *) emalloc(3);
  1003.     overnames[oi][0] = vals[0];
  1004.     overnames[oi][1] = vals[1];
  1005.     overnames[oi][2] = 0;
  1006.     return oi++;
  1007. }
  1008.  
  1009. static int
  1010. linematch(havetype, havecount, wanttype, wantlo, wanthi)
  1011. const char * const    havetype;
  1012. int const        havecount;
  1013. const char * const    wanttype;
  1014. int const        wantlo;
  1015. int const        wanthi;
  1016. {
  1017.     if (strcmp(havetype, wanttype) != 0)
  1018.         return FALSE;
  1019.     if (havecount < wantlo || havecount > wanthi)
  1020.         wildline("number of fields");
  1021.     return TRUE;
  1022. }
  1023.  
  1024. static void
  1025. loadsub(filename)
  1026. const char * const    filename;
  1027. {
  1028.     FILE *    fp;
  1029.     char *    line;
  1030.     item *    ip;
  1031.     int    fti;
  1032.     int    i;
  1033.     int    n;
  1034.     int    font;
  1035.     int    width;
  1036.     int        size;
  1037.     char        t[BUFSIZ];
  1038.     char        f[9][BUFSIZ];
  1039.  
  1040.     fp = dfopen(filename, "r", TRUE);
  1041.     for (i = 0; i < 9; ++i)
  1042.         f[i][0] = '\0';
  1043.     while ((line = getline(fp)) != NULL) {
  1044.         n = sscanf(line, "%s %s %s %s %s %s %s %s",
  1045.             t, f[2], f[3], f[4],
  1046.             f[5], f[6], f[7], f[8]);
  1047.         for (i = 2; i <= n; ++i)
  1048.             disescape(f[i]);
  1049.         /*
  1050.         ** NEWPAGE data
  1051.         */
  1052.         if (linematch(t, n, "NEWPAGE", 2, 2)) {
  1053.             newpage = ecpyalloc(f[2]);
  1054.             continue;
  1055.         }
  1056.         /*
  1057.         ** PORTRAIT data
  1058.         */
  1059.         if (linematch(t, n, "PORTRAIT", 2, 2)) {
  1060.             portrait = ecpyalloc(f[2]);
  1061.             continue;
  1062.         }
  1063.         /*
  1064.         ** LANDSCAPE data
  1065.         */
  1066.         if (linematch(t, n, "LANDSCAPE", 2, 2)) {
  1067.             landscape = ecpyalloc(f[2]);
  1068.             continue;
  1069.         }
  1070.         /*
  1071.         ** DOWNORIENT--always portrait for now.
  1072.         */
  1073.         if (linematch(t, n, "DOWNORIENT", 1, 1)) {
  1074.             LJ_sput(portrait);
  1075.             continue;
  1076.         }
  1077.         /*
  1078.         ** LEFTMARGIN size
  1079.         */
  1080.         if (linematch(t, n, "LEFTMARGIN", 2, 2)) {
  1081.             if (sscanf(f[2], scheck(f[2], "%d"),
  1082.                 &leftmargin) != 1 || leftmargin < 0)
  1083.                     wildline("left margin");
  1084.             continue;
  1085.         }
  1086.         /*
  1087.         ** WIDTHUNITSPERINCH size
  1088.         */
  1089.         if (linematch(t, n, "WIDTHUNITSPERINCH", 2, 2)) {
  1090.             if (sscanf(f[2], scheck(f[2], "%f"), &lwupi) != 1 ||
  1091.                 lwupi <= 0)
  1092.                     wildline("width units per inch");
  1093.             continue;
  1094.         }
  1095.         /*
  1096.         ** WIDTHPOINTSIZE size
  1097.         */
  1098.         if (linematch(t, n, "WIDTHPOINTSIZE", 2, 2)) {
  1099.             if (sscanf(f[2], scheck(f[2], "%f"), &lwps) != 1 ||
  1100.                 lwps <= 0)
  1101.                     wildline("width point size");
  1102.             continue;
  1103.         }
  1104.         /*
  1105.         ** LOWCHAR value string
  1106.         */
  1107.         if (linematch(t, n, "LOWCHAR", 3, 3)) {
  1108.             if (sscanf(f[2], scheck(f[2], "%d"), &lowvalue) != 1 ||
  1109.                 lowvalue <= 0)
  1110.                     wildline("low value");
  1111.             lowstring = ecpyalloc(f[3]);
  1112.             continue;
  1113.         }
  1114.         /*
  1115.         ** CPI size
  1116.         */
  1117.         if (linematch(t, n, "CPI", 2, 2)) {
  1118.             if (sscanf(f[2], scheck(f[2], "%f"), &lcpi) != 1 ||
  1119.                 lcpi <= 0)
  1120.                     wildline("CPI");
  1121.             continue;
  1122.         }
  1123.         /*
  1124.         ** INCLUDE filename
  1125.         */
  1126.         if (linematch(t, n, "INCLUDE", 2, 2)) {
  1127.             loadsub(f[2]);
  1128.             continue;
  1129.         }
  1130.         /*
  1131.         ** DOWNDATA data
  1132.         */
  1133.         if (linematch(t, n, "DOWNDATA", 2, 2)) {
  1134.             LJ_sput(f[2]);
  1135.             continue;
  1136.         }
  1137.         /*
  1138.         ** ENDDATA data
  1139.         */
  1140.         if (linematch(t, n, "ENDDATA", 2, 2)) {
  1141.             enddata = ecpyalloc(f[2]);
  1142.             continue;
  1143.         }
  1144.         /*
  1145.         ** DOWNFILE filename
  1146.         */
  1147.         if (linematch(t, n, "DOWNFILE", 2, 2)) {
  1148.             FILE *    dfp;
  1149.             char *    cp;
  1150.             int    c;
  1151.  
  1152.             cp = ecpyalloc(f[2]);
  1153.             cp = ecatalloc(cp, ".D");
  1154.             dfp = dfopen(cp, "r", TRUE);
  1155.             free(cp);
  1156.             while ((c = getc(dfp)) != EOF)
  1157.                 LJ_cput(c);
  1158.             if (ferror(dfp) || !feof(dfp) || fclose(dfp))
  1159.                 wildline("result from downloading");
  1160.             continue;
  1161.         }
  1162.         /*
  1163.         ** FORGET charname
  1164.         */
  1165.         if (linematch(t, n, "FORGET", 2, 2)) {
  1166.             fti = nametoindex(f[2]);
  1167.             ip = &items[fti];
  1168.             ip->ssname = ip->inset =
  1169.                 ip->outset = ip->data = NULL;
  1170.             ip->waschar = FALSE;
  1171.             continue;
  1172.         }
  1173.         /*
  1174.         ** UNITSPERINCH horizontal vertical
  1175.         */
  1176.         if (linematch(t, n, "UNITSPERINCH", 3, 3)) {
  1177.             int    hupi;
  1178.             int    vupi;
  1179.  
  1180.             if (sscanf(f[2], scheck(f[2], "%d"),
  1181.                 &hupi) != 1 ||
  1182.                 hupi <= 0)
  1183.                     wildline("horizontal UNITSPERINCH");
  1184.             if (sscanf(f[2], scheck(f[2], "%d"),
  1185.                 &vupi) != 1 ||
  1186.                 vupi <= 0)
  1187.                     wildline("vertical UNITSPERINCH");
  1188.             if (horunitsperinch != 0 &&
  1189.                 (horunitsperinch != hupi ||
  1190.                 verunitsperinch != vupi))
  1191.                     wildline("repeated UNITSPERINCH");
  1192.             horunitsperinch = hupi;
  1193.             verunitsperinch = vupi;
  1194.             continue;
  1195.         }
  1196.         /*
  1197.         ** MOVES horizontal-move vertical-move
  1198.         */
  1199.         if (linematch(t, n, "MOVES", 3, 3)) {
  1200.             hormove = ecpyalloc(f[2]);
  1201.             vermove = ecpyalloc(f[3]);
  1202.             continue;
  1203.         }
  1204.         /*
  1205.         ** FONT name in    out
  1206.         */
  1207.         if (linematch(t, n, "FONT", 4, 4)) {
  1208.             for (font = 0; font < NFONTS; ++font) {
  1209.                 if (strcmp(f[2],
  1210.                     fontdata[font].f_fontnick) != 0)
  1211.                         continue;
  1212.                 fontdata[font].f_in = ecpyalloc(f[3]);
  1213.                 fontdata[font].f_out = ecpyalloc(f[4]);
  1214.                 break;
  1215.             }
  1216.             if (font == NFONTS)
  1217.                 wildline("unknown font name");
  1218.             continue;
  1219.         }
  1220.         /*
  1221.         ** SIZES in
  1222.         */
  1223.         if (linematch(t, n, "SIZES", 2, 2)) {
  1224.             sizes = ecatalloc(sizes, f[2]);
  1225.             continue;
  1226.         }
  1227.         /*
  1228.         ** FIRST pointsize font in
  1229.         */
  1230.         if (linematch(t, n, "FIRST", 4, 4)) {
  1231.             if (sscanf(f[2], scheck(f[2], "%d"), &size) != 1 ||
  1232.                 size < 0 ||
  1233.                 size >= sizeof firsts / sizeof firsts[0])
  1234.                     wildline("size");
  1235.             for (i = 0; ; ++i) {
  1236.                 if (i >= NFONTS)
  1237.                     wildline("font");
  1238.                 if (strcmp(f[3], fontdata[i].f_fontnick) != 0)
  1239.                     continue;
  1240.                 firsts[size][i] = ecatalloc(firsts[size][i],
  1241.                     f[4]);
  1242.                 break;
  1243.             }
  1244.             continue;
  1245.         }
  1246.         /*
  1247.         ** Need width for rest.
  1248.         */
  1249.         if (lwupi == 0)
  1250.             wildline("missing WIDTHUNITSPERINCH line");
  1251.         if (lwps == 0)
  1252.             wildline("missing WIDTHPOINTSIZE line");
  1253.         if (horunitsperinch == 0 || verunitsperinch == 0)
  1254.             wildline("missing UNITSPERINCH line");
  1255.         /*
  1256.         ** SYMBOLS filename [in [out]]
  1257.         ** If cpi != 0 and there's no width file,
  1258.         ** all widths are set to lwupi / lcpi.
  1259.         */
  1260.         if (linematch(t, n, "SYMBOLS", 2, 4)) {
  1261.             FILE *        sfp;
  1262.             const char *    cp;
  1263.             char *        template;
  1264.             char *        names[NI];
  1265.             char *        rwidths[NI];
  1266.             char *        iwidths[NI];
  1267.             char *        bwidths[NI];
  1268.             int        didr;
  1269.             int        didib;
  1270.             char *        ssname;
  1271.             char *        inset;
  1272.             char *        outset;
  1273.  
  1274.             ssname = ecpyalloc(f[2]);
  1275.             inset = (n <= 2) ? NULL : ecpyalloc(f[3]);
  1276.             outset = (n <= 3) ? NULL : ecpyalloc(f[4]);
  1277.             template = ecpyalloc(ssname);
  1278.             template = ecatalloc(template, ".X");
  1279.             template[strlen(template) - 1] = 'M';
  1280.             sfp = dfopen(template, "r", TRUE);
  1281.             cp = namefor(sfp);
  1282.             (void) fclose(sfp);
  1283.             getnames(cp, names);
  1284.             template[strlen(template) - 1] = 'R';
  1285.             sfp = dfopen(template, "r", lcpi == 0);
  1286.             didib = FALSE;
  1287.             if (sfp == NULL)
  1288.                 didr = FALSE;
  1289.             else {
  1290.                 didr = TRUE;
  1291.                 cp = namefor(sfp);
  1292.                 (void) fclose(sfp);
  1293.                 getnames(cp, rwidths);
  1294.  
  1295.                 template[strlen(template) - 1] = 'I';
  1296.                 sfp = dfopen(template, "r", FALSE);
  1297.                 if (sfp != NULL) {
  1298.                     didib = TRUE;
  1299.                     cp = namefor(sfp);
  1300.                     (void) fclose(sfp);
  1301.                     getnames(cp, iwidths);
  1302.  
  1303.                     template[strlen(template) - 1] = 'B';
  1304.                     sfp = dfopen(template, "r", TRUE);
  1305.                     cp = namefor(sfp);
  1306.                     (void) fclose(sfp);
  1307.                     getnames(cp, bwidths);
  1308.                 }
  1309.             }
  1310.             for (i = 0; i < NI; ++i) {
  1311.                 if (names[i] == NULL)
  1312.                     continue;
  1313.                 fti = nametoindex(names[i]);
  1314.                 ip = &items[fti];
  1315.                 if (ip->ssname != NULL)
  1316.                     continue;
  1317.                 ip->ssname = ssname;
  1318.                 ip->inset = inset;
  1319.                 ip->outset = outset;
  1320.                 ip->data = emalloc(2);
  1321.                 ip->data[0] = i;
  1322.                 ip->data[1] = '\0';
  1323.                 for (font = 0; font < NFONTS; ++font) {
  1324.                     if (!didr)
  1325.                         width = lwupi / lcpi;
  1326.                     else {
  1327.                         cp = rwidths[i];
  1328.                         if (didib)
  1329.                             if (fontisB(font))
  1330.                                 cp = bwidths[i];
  1331.                             else if (fontisI(font))
  1332.                                 cp = iwidths[i];
  1333.                         if (cp == NULL)
  1334.                             width = 0;
  1335.                         else    width = atoi(cp);
  1336.                     }
  1337.                     ip->lwidths[font] = width;
  1338.                     ip->widths[font] = lwtocw(i, font,
  1339.                         width);
  1340.                 }
  1341.             }
  1342.             continue;
  1343.         }
  1344.         /*
  1345.         ** And last but not least. . .
  1346.         ** CHAR charname symbolset data [wideas offset]
  1347.         */
  1348.         if (linematch(t, n, "CHAR", 4, 6)) {
  1349.             char *    cp;
  1350.             int        off;
  1351.  
  1352.             if (n < 6)
  1353.                 off = 0;
  1354.             else if (sscanf(f[6], scheck(f[6], "%d"), &off) != 1)
  1355.                 wildline("offset");
  1356.             fti = nametoindex(f[2]);
  1357.             ip = &items[fti];
  1358.             if (n == 4 && ip->ssname == NULL &&
  1359.                 strcmp(f[2], "br") != 0)
  1360.                     wildline("missing width w/o old width");
  1361.             if (ip->waschar)
  1362.                 wildline("multiple lines for same CHAR");
  1363.             ip->waschar = TRUE;
  1364.             for (i = 0; i < NI; ++i) {
  1365.                 item *    jp;
  1366.  
  1367.                 jp = &items[i];
  1368.                 if (jp->ssname != NULL &&
  1369.                     strcmp(jp->ssname, f[3]) == 0)
  1370.                         break;
  1371.             }
  1372.             if (i >= NI)
  1373.                 wildline("CHAR symbol set");
  1374.             ip->ssname = items[i].ssname;
  1375.             ip->inset = items[i].inset;
  1376.             ip->outset = items[i].outset;
  1377.             ip->data = ecpyalloc(f[4]);
  1378.             if (n == 4)
  1379.                 continue;
  1380.             for (font = 0; font < NFONTS; ++font) {
  1381.                 int    w;
  1382.  
  1383.                 w = off;
  1384.                 for (cp = f[5]; *cp != '\0'; ++cp) {
  1385.                     if (items[(int) *cp].ssname == NULL)
  1386.                         wildline("'wide as' string");
  1387.                     w += items[(int) *cp].lwidths[font];
  1388.                 }
  1389.                 ip->lwidths[font] = w;
  1390.                 ip->widths[font] = lwtocw(fti, font, w);
  1391.             }
  1392.             continue;
  1393.         }
  1394.         wildline("line of unknown type");
  1395.     }
  1396. }
  1397.  
  1398. static void
  1399. loadinfo()
  1400. {
  1401.     item *    ip;
  1402.     int    i;
  1403.     int    j;
  1404.     int    font;
  1405.  
  1406.     loadsub("table");
  1407.     if (hormove == NULL || vermove == NULL)
  1408.         wildexit("missing MOVES line in table");
  1409.     /*
  1410.     ** Characters with multiple width table indices
  1411.     */
  1412.     i = ntn2fti("ul");
  1413.     j = '_';
  1414.     if (items[i].ssname == NULL)
  1415.         items[i] = items[j];
  1416.     else if (items[j].ssname == NULL)
  1417.         items[j] = items[i];
  1418.     i = ntn2fti("hy");
  1419.     j = '-';
  1420.     if (items[i].ssname == NULL)
  1421.         items[i] = items[j];
  1422.     else if (items[j].ssname == NULL)
  1423.         items[j] = items[i];
  1424.     /*
  1425.     ** Overstrike widths.
  1426.     */
  1427.     for (i = NI; overnames[i] != NULL && overnames[i][0] != '\0'; ++i) {
  1428.         ip = &items[overnames[i][0]];
  1429.         for (font = 0; font < NFONTS; ++font)
  1430.             items[i].widths[font] = ip->widths[font];
  1431.         ip = &items[overnames[i][1]];
  1432.         for (font = 0; font < NFONTS; ++font)
  1433.             if (ip->widths[font] > items[i].widths[font])
  1434.                 items[i].widths[font] = ip->widths[font];
  1435.     }
  1436.     if (!vflag)
  1437.         return;
  1438.     (void) printf("CHAR[S]\tSYMBOLSET  %c%c%c%c WIDTHS    DATA\n",
  1439.         *fontdata[0].f_fontnick, *fontdata[1].f_fontnick,
  1440.         *fontdata[2].f_fontnick, *fontdata[3].f_fontnick);
  1441.     for (i = 0;
  1442.         i < NI || (overnames[i] != NULL && overnames[i][0] != '\0');
  1443.         ++i) {
  1444.         ip = &items[i];
  1445.         if (ip->ssname == NULL)
  1446.             continue;
  1447.         if (i < NI)
  1448.             (void) printf("%s", fti2ntn(i));
  1449.         else    (void) printf("%s %s", fti2ntn((int) overnames[i][0]),
  1450.                 fti2ntn((int) overnames[i][1]));
  1451.         (void) printf("\t%-9s", ip->ssname);
  1452.         for (font = 0; font < NFONTS; ++font)
  1453.             (void) printf("%4d", ip->widths[font]);
  1454.         (void) printf(" ");
  1455.         for (j = 0; ip->data[j] != '\0'; ++j) {
  1456.             int    c;
  1457.  
  1458.             c = ip->data[j];
  1459.             if (isascii(c) && isprint(c) && c != ' ')
  1460.                 (void) putchar(c);
  1461.             else if (c == '\033')
  1462.                 (void) printf("\\E");
  1463.             else    (void) printf("\\%03o", (unsigned char) c);
  1464.         }
  1465.         (void) printf("\n");
  1466.     }
  1467. }
  1468.  
  1469. static void
  1470. LJ_cput(c)
  1471. int const    c;
  1472. {
  1473.     if (!wflag)
  1474.         (void) putchar(c);
  1475. }
  1476.  
  1477. static void
  1478. LJ_sput(s)
  1479. const char *    s;
  1480. {
  1481.     int    c;
  1482.  
  1483.     if (s == NULL)
  1484.         return;
  1485.     while ((c = *s++) != '\0')
  1486.         LJ_cput(c);
  1487. }
  1488.  
  1489. static void
  1490. LJ_fdput(f, d)
  1491. const char * const    f;
  1492. int const        d;
  1493. {
  1494. /*
  1495. ** 302 / 1000 is log10(2.0) rounded up.
  1496. ** Subtract one for the sign bit;
  1497. ** add one for integer division truncation;
  1498. ** add one more for a minus sign.
  1499. */
  1500. #define INT_STRLEN_MAXIMUM(type) \
  1501.     ((sizeof(type) * CHAR_BIT - 1) * 302 / 1000 + 2)
  1502.  
  1503.     static char *    buf;
  1504.     static int    bufsize;
  1505.     int        wantsize;
  1506.  
  1507.     wantsize = strlen(f) + INT_STRLEN_MAXIMUM(int) + 1;
  1508.     if (wantsize > bufsize) {
  1509.         ifree(buf);
  1510.         buf = emalloc(wantsize);
  1511.         bufsize = wantsize;
  1512.     }
  1513.     (void) sprintf(buf, f, d);
  1514.     LJ_sput(buf);
  1515. }
  1516.  
  1517. static void
  1518. swift(afont, wfont)
  1519. int const    afont;
  1520. int const    wfont;
  1521. {
  1522.     if (afont >= 0)
  1523.         LJ_sput(fontdata[afont].f_out);
  1524.     LJ_sput(fontdata[wfont].f_in);
  1525. }
  1526.  
  1527. static void
  1528. dostrike(s)
  1529. strike    s;
  1530. {
  1531.     item *        ip;
  1532.     static long    achor = -1;
  1533.     static long    acver = -1;
  1534.     static int    afont = -1;
  1535.     static int    asize = -1;
  1536.     static int    apage = -1;
  1537.     static item *    curip;
  1538.     static item *    oldip;
  1539.     static int    called;
  1540.  
  1541.     if (s.fti <= 0)
  1542.         return;
  1543.     /*
  1544.     ** First time downloading.
  1545.     */
  1546.     if (firsts[s.size][s.font] != NULL) {
  1547.         FILE *    fp;
  1548.         char *    cp;
  1549.         char *    dp;
  1550.         int    c;
  1551.  
  1552.         cp = firsts[s.size][s.font];
  1553.         firsts[s.size][s.font] = NULL;
  1554.         while ((c = *cp++) != '\0') {
  1555.             if (c != '<') {
  1556.                 LJ_cput(c);
  1557.                 continue;
  1558.             }
  1559.             dp = cp;
  1560.             while (*dp != '\0' && *dp != '>')
  1561.                 ++dp;
  1562.             if (*dp == '\0') {
  1563.                 LJ_cput(c);
  1564.                 continue;
  1565.             }
  1566.             *dp = '\0';
  1567.             /*
  1568.             ** Download the file.
  1569.             */
  1570.             if ((fp = fopen(cp, "r")) == NULL)
  1571.                 wild2exit("result opening", cp);
  1572.             while ((c = getc(fp)) != EOF)
  1573.                 LJ_cput(c);
  1574.             if (ferror(fp) || !feof(fp) || fclose(fp))
  1575.                 wildexit("result from downloading");
  1576.             *dp++ = '>';
  1577.             cp = dp;
  1578.         }
  1579.         curip = NULL;    /* to get font reselection */
  1580.     }
  1581.     ip = &items[s.fti];
  1582.     /*
  1583.     ** Easiest part first.
  1584.     */
  1585.     if (curip != NULL && curip->outset != NULL &&
  1586.         curip->ssname != ip->ssname) {
  1587.             LJ_sput(curip->outset);
  1588.             curip = oldip;
  1589.             oldip = NULL;
  1590.     }
  1591.     if (curip == NULL || ip->ssname != curip->ssname) {
  1592.         LJ_sput(ip->inset);
  1593.         if (ip->outset != NULL)
  1594.             oldip = curip;
  1595.         curip = ip;
  1596.     }
  1597.     /*
  1598.     ** Get to right page; modulate vertical offset.
  1599.     */
  1600.     {
  1601.         int    wpage;
  1602.  
  1603.         wpage = s.ver / ncvupp;
  1604.         if (wpage != apage) {
  1605.  
  1606.             if (called)
  1607.                 LJ_sput(newpage);
  1608.             apage = wpage;
  1609.             acver = 0;
  1610.         }
  1611.         s.ver %= ncvupp;
  1612.     }
  1613.     /*
  1614.     ** Get to right horizontal place.
  1615.     */
  1616.     /*
  1617.     ** Always position repeated root ens and underlines.
  1618.     */
  1619.     {
  1620.         static int    didindices;
  1621.         static int    rnindex;
  1622.         static int    ulindex;
  1623.         static int    _index;
  1624.         static int    dotindex;
  1625.         static int    prev;
  1626.  
  1627.         if (!didindices) {
  1628.             didindices = TRUE;
  1629.             rnindex = ntn2fti("rn");
  1630.             ulindex = ntn2fti("ul");
  1631.             _index = ntn2fti("_");
  1632.             dotindex = ntn2fti(".");
  1633.         }
  1634.         if (s.fti == prev &&
  1635.             (s.fti == rnindex ||
  1636.             s.fti == ulindex ||
  1637.             s.fti  == _index ||
  1638.             s.fti == dotindex))
  1639.                 achor = ~s.hor;
  1640.         prev = s.fti;
  1641.     }
  1642.     if (s.hor != achor) {
  1643.         long    wlhor;
  1644.         static long    adjustment;
  1645.  
  1646.         wlhor = s.hor * horunitsperinch / NCHUPI;
  1647.         /*
  1648.         ** Adjust for stupid left margin.
  1649.         */
  1650.         if (wlhor < leftmargin)
  1651.             adjustment = leftmargin;
  1652.         wlhor += adjustment;
  1653.         /*
  1654.         ** Rustproofing.
  1655.         */
  1656.         if (wlhor < 0)
  1657.             wlhor = 0;
  1658.         LJ_fdput(hormove, (int) wlhor);
  1659.         achor = s.hor;
  1660.     }
  1661.     /*
  1662.     ** Get to right vertical place.
  1663.     */
  1664.     {
  1665.         long    wlver;
  1666.  
  1667.         if (s.ver != acver) {
  1668.             wlver = (long) s.ver * verunitsperinch / NCVUPI;
  1669.             /*
  1670.             ** Rustproofing.
  1671.             */
  1672.             if (wlver < 0)
  1673.                 wlver = 0;
  1674.             LJ_fdput(vermove, (int) wlver);
  1675.             acver = s.ver;
  1676.         }
  1677.     }
  1678.     /*
  1679.     ** If haven't already changed font. . .
  1680.     */
  1681.     if (afont != s.font) {
  1682.         swift(afont, s.font);
  1683.         afont = s.font;
  1684.     }
  1685.     if (asize != s.size) {
  1686.         LJ_fdput(sizes, s.size);
  1687.         asize = s.size;
  1688.     }
  1689.     /*
  1690.     ** Quote if necessary.
  1691.     */
  1692.     if (ip->data != NULL && ip->data[0] != 0 && ip->data[1] == 0 &&
  1693.         lowvalue != 0 && ip->data[0] < lowvalue)
  1694.             LJ_sput(lowstring);
  1695.     /*
  1696.     ** Finally send out the data.
  1697.     */
  1698.     if (ip->data != NULL)
  1699.         LJ_sput(ip->data);
  1700.     else if (isascii(s.fti) && isprint(s.fti))
  1701.         LJ_cput(s.fti);
  1702.     else    LJ_cput('\177'); /* make this settable? */
  1703.     /*
  1704.     ** Update horizontal position.
  1705.     */
  1706.     achor += fiswidth(s.font, s.fti, s.size);
  1707.     called = TRUE;
  1708. }
  1709.  
  1710. /*
  1711. ** The stuff below is used only when generating width tables for use with troff.
  1712. */
  1713.  
  1714. static int
  1715. ascends(name)
  1716. const char *    name;
  1717. {
  1718.     if (name[1] == '\0')
  1719.         return isdigit(name[0]) || isupper(name[0]) ||
  1720.             strchr("bdfhijklt", name[0]) != 0;
  1721.     switch (*name++) {
  1722.         case '*': return strchr("bdzhlcfqGDHLCPSUFQW", *name) != 0;
  1723.         case 'f': return strchr("ilf", *name) != 0;
  1724.         case 'F': return strchr("il", *name) != 0;
  1725.         case 'g': return *name == 'r';
  1726.     }
  1727.     return FALSE;
  1728. }
  1729.  
  1730. static int
  1731. descends(name)
  1732. const char * const    name;
  1733. {
  1734.     if (name[1] == '\0')
  1735.         return strchr("Qgjpqy", name[0]) != 0;
  1736.     if (name[0] == '*')
  1737.         return strchr("bgzymcrfxq", name[1]) != 0;
  1738.     return strcmp(name, "ts") == 0;
  1739. }
  1740.  
  1741. static void
  1742. dowidth()
  1743. {
  1744.     FILE *        fp;
  1745.     char *        cp;
  1746.     const char *    name;
  1747.     item *        ip;
  1748.     int        font;
  1749.     int        j;
  1750.     int        w;
  1751.  
  1752.     for (font = 0; font < NFONTS; ++font) {
  1753.         cp = ecpyalloc("ft");
  1754.         cp = ecatalloc(cp, fontdata[font].f_fontnick);
  1755.         fp = dfopen(cp, "w", TRUE);
  1756.         free(cp);
  1757.         for (j = 0; j < 256; ++j) {
  1758.             if ((name = fti2ntn(j)) == NULL) {
  1759.                 (void) putc(0, fp);
  1760.                 continue;
  1761.             }
  1762.             if (fontisS(font) ? ntnonr(name) : ntnons(name)) {
  1763.                 (void) putc(0, fp);
  1764.                 continue;
  1765.             }
  1766.             if (strcmp(name, "\\^") == 0) 
  1767.                 w = (NCHUPI * CWPS) / (NPPI * 12); /* 1/12 em */
  1768.             else if (strcmp(name, "\\|") == 0)
  1769.                 w = (NCHUPI * CWPS) / (NPPI * 6); /* 1/6 em */
  1770.             else {
  1771.                 ip = &items[j];
  1772.                 if (ip->ssname == NULL) {
  1773.                     (void) putc(0, fp);
  1774.                     continue;
  1775.                 }
  1776.                 w = ip->widths[font];
  1777.                 if (ascends(name))
  1778.                     w |= 0200;
  1779.                 if (descends(name))
  1780.                     w |= 0100;
  1781.             }
  1782.             (void) putc(w, fp);
  1783.         }
  1784.         if (ferror(fp) || fclose(fp))
  1785.             wildline("result writing");
  1786.     }
  1787. }
  1788.