home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume19 / dvi / part02 < prev    next >
Text File  |  1991-05-14  |  46KB  |  1,797 lines

  1. Newsgroups: comp.sources.misc
  2. From: Parag Patel <parag@hpsdeb.sde.hp.com>
  3. Subject:  v19i065:  dvi - C++ DVI filter for HP LaserJets, Part02/03
  4. Message-ID: <1991May14.182308.14288@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: feea4f2eda05ef0247b22ce6831230ca
  6. Date: Tue, 14 May 1991 18:23:08 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Parag Patel <parag@hpsdeb.sde.hp.com>
  10. Posting-number: Volume 19, Issue 65
  11. Archive-name: dvi/part02
  12.  
  13. ---- Cut Here and feed the following to sh ----
  14. #!/bin/sh
  15. # This is part 02 of dvi
  16. # ============= stack.C ==============
  17. if test -f 'stack.C' -a X"$1" != X"-c"; then
  18.     echo 'x - skipping stack.C (File already exists)'
  19. else
  20. echo 'x - extracting stack.C (Text)'
  21. sed 's/^X//' << 'SHAR_EOF' > 'stack.C' &&
  22. // Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
  23. static const char rcsid[] = "$Header: stack.C,v 1.7 91/02/22 15:57:07 hmgr Exp $";
  24. X
  25. // manipulate a DVI stack
  26. //
  27. // by Parag Patel
  28. X
  29. #include "defs.h"
  30. X
  31. X
  32. // a stack representation
  33. struct stkrep
  34. {
  35. X    double h, v, w, x, y, z;
  36. };
  37. X
  38. declare_array(Stack, stkrep);
  39. implement_array(Stack, stkrep);
  40. X
  41. static int top = 0;            // top of the stack;
  42. static Stack sp(50);            // the DVI stack itself
  43. X
  44. X
  45. // save current DVI/TeX variable values
  46. // 
  47. void pushdvi()
  48. {
  49. X    sp[top].h = H;
  50. X    sp[top].v = V;
  51. X    sp[top].w = W;
  52. X    sp[top].x = X;
  53. X    sp[top].y = Y;
  54. X    sp[top].z = Z;
  55. X    top++;
  56. }
  57. X
  58. X
  59. // restore current DVI/TeX variable values
  60. // 
  61. void popdvi()
  62. {
  63. X    if (top <= 0)
  64. X    quit("Stack underflow");
  65. X    top--;
  66. X    H = sp[top].h;
  67. X    V = sp[top].v;
  68. X    W = sp[top].w;
  69. X    X = sp[top].x;
  70. X    Y = sp[top].y;
  71. X    Z = sp[top].z;
  72. }
  73. X
  74. X
  75. // clear the stack and dvi vars
  76. // 
  77. void cleardvi()
  78. {
  79. X    H = V = W = X = Y = Z = 0.0;
  80. X    top = 0;
  81. }
  82. SHAR_EOF
  83. chmod 0444 stack.C ||
  84. echo 'restore of stack.C failed'
  85. Wc_c="`wc -c < 'stack.C'`"
  86. test 970 -eq "$Wc_c" ||
  87.     echo 'stack.C: original size 970, current size' "$Wc_c"
  88. fi
  89. # ============= dirs.C ==============
  90. if test -f 'dirs.C' -a X"$1" != X"-c"; then
  91.     echo 'x - skipping dirs.C (File already exists)'
  92. else
  93. echo 'x - extracting dirs.C (Text)'
  94. sed 's/^X//' << 'SHAR_EOF' > 'dirs.C' &&
  95. // Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
  96. static const char rcsid[] = "$Header: dirs.C,v 1.10 91/02/22 15:57:16 hmgr Exp $";
  97. X
  98. // read font directory names into memory for fast traversal
  99. //
  100. // by Parag Patel
  101. X
  102. #include "defs.h"
  103. #include "dirs.h"
  104. #ifdef    __ZTC__
  105. #include <dos.h>
  106. #define    d_name    name
  107. #else
  108. #ifdef    BSD
  109. #include <sys/dir.h>
  110. #else
  111. #include <ndir.h>
  112. #endif
  113. #endif
  114. X
  115. X
  116. implement_array(Dirlist, Dirent);
  117. implement_array(Pathlist, Pathent);
  118. X
  119. X
  120. Pathlist pathlist;
  121. X
  122. X
  123. Dirent::Dirent()
  124. {
  125. X    name = NULL;
  126. X    val = 0;
  127. }
  128. X
  129. Pathent::Pathent()
  130. {
  131. X    path = NULL;
  132. }
  133. X
  134. Pathent &Pathent::operator=(Pathent &x)
  135. {
  136. X    path = x.path;
  137. X    dirs = x.dirs;
  138. X    return *this;
  139. }
  140. X
  141. X
  142. void setupdirs(char *path)
  143. {
  144. X    path = strdup(path);
  145. X    char *save = path;
  146. X
  147. X    pathlist.reset();
  148. X
  149. X    debug(3, "Setup dirpaths = %s", path);
  150. X    while (path != NULL && *path != '\0')
  151. X    {
  152. X    char *dirpath = path;
  153. X    while (*path != PATHSEP && *path != '\0')
  154. X        path++;
  155. X    if (*path != '\0')
  156. X        *path++ = '\0';
  157. X    debug(4, "  DIR = %s", dirpath);
  158. X
  159. #ifndef    __ZTC__
  160. X    DIR *dir = opendir(dirpath);
  161. X    if (dir == NULL)
  162. X    {
  163. X        warn("Cannot opendir directory \"%s\" for scanning", dirpath);
  164. X        continue;
  165. X    }
  166. #endif
  167. X
  168. X    Pathent & path = pathlist[pathlist.size()];
  169. X    path.path = strdup(dirpath);
  170. X    path.dirs.reset();
  171. X
  172. #ifdef    __ZTC__
  173. X    char dos_dirpath[64];
  174. X    (void)strcpy(dos_dirpath, dirpath);
  175. X    (void)strcat(dos_dirpath, "/*.*");
  176. X    for (FIND *ent = findfirst(dos_dirpath, FA_DIREC); ent != NULL;
  177. X        ent = findnext())
  178. #else
  179. X    for (direct * ent = readdir(dir); ent != NULL; ent = readdir(dir))
  180. #endif
  181. X    {
  182. X        char *s = strchr(ent->d_name, '.');
  183. X        int magent;
  184. X
  185. X        if (s != NULL)
  186. X        {
  187. X        // if there is a dot in the name, it may be the newer
  188. X        // magnification value naming conventions: "1.000"
  189. X        *s = '\0';
  190. X        magent = atoi(ent->d_name) * 1000 + atoi(s + 1);
  191. X        *s = '.';
  192. X        }
  193. X        else
  194. X        // older resolution naming convention: "300", "1000"
  195. X        magent = atoi(ent->d_name);
  196. X
  197. X        if (magent <= 0)
  198. X        continue;
  199. X
  200. X        Dirent & d = path.dirs[path.dirs.size()];
  201. X        d.name = strdup(ent->d_name);
  202. X        d.val = magent;
  203. X        debug(5, "    name=%s  val=%d", d.name, d.val);
  204. X    }
  205. X
  206. #ifndef    __ZTC__
  207. X    closedir(dir);
  208. #endif
  209. X    }
  210. X    strfree(save);
  211. }
  212. SHAR_EOF
  213. chmod 0444 dirs.C ||
  214. echo 'restore of dirs.C failed'
  215. Wc_c="`wc -c < 'dirs.C'`"
  216. test 2199 -eq "$Wc_c" ||
  217.     echo 'dirs.C: original size 2199, current size' "$Wc_c"
  218. fi
  219. # ============= dvi.C ==============
  220. if test -f 'dvi.C' -a X"$1" != X"-c"; then
  221.     echo 'x - skipping dvi.C (File already exists)'
  222. else
  223. echo 'x - extracting dvi.C (Text)'
  224. sed 's/^X//' << 'SHAR_EOF' > 'dvi.C' &&
  225. // Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
  226. static const char rcsid[] = "$Header: dvi.C,v 1.24 91/02/22 15:57:33 hmgr Exp $";
  227. X
  228. // dvi scanning routines
  229. //
  230. // by Parag Patel
  231. X
  232. #include "defs.h"
  233. X
  234. X
  235. static long mag = 1000;
  236. static double magval = 1.0;
  237. X
  238. X
  239. // print the specified page from the file "fp" at the specified
  240. // magnification - this is called for any page in the DVI file provided
  241. // that the "fp" has been set to the start of a page in the DVI file -
  242. // thus pages may be printed in any random order
  243. // 
  244. static void dopage(FILE *fp, long page)
  245. {
  246. X    // clear and initialize the global state for a new page
  247. X    cleardvi();
  248. X    clearfonts();
  249. X
  250. X    // if this is not the first page, then eject the previous
  251. X    // page from the printer
  252. X    // 
  253. X    static first = TRUE;
  254. X    dev_newpage((page & 0x01) || page == 0, first);
  255. X    first = FALSE;
  256. X
  257. X    // now go through the DVI file executing opcodes...
  258. X    register int opcode;
  259. X    while ((opcode = (int)getuval(1, fp)) != EOP)
  260. X    {
  261. X    debug(7, "    H=%f V=%f  W=%f X=%f  Y=%f Z=%f", H, V, W, X, Y, Z);
  262. X    debug(6, "opcode = %d", opcode);
  263. X
  264. X    if (opcode >= SET0 && opcode <= SET127)
  265. X    {
  266. X        // typeset (print) a character
  267. X        typeset(opcode, TRUE, magval);
  268. X        continue;
  269. X    }
  270. X    if (opcode >= FONT0 && opcode <= FONT63)
  271. X    {
  272. X        // switch to a new font
  273. X        newfont(opcode - FONT0);
  274. X        continue;
  275. X    }
  276. X    switch (opcode)
  277. X    {
  278. X        // print (typeset) a character and move the cursor
  279. X    Case SET1: 
  280. X        typeset(getuval(1, fp), TRUE, magval);
  281. X    Case SET2: 
  282. X        typeset(getuval(2, fp), TRUE, magval);
  283. X    Case SET3: 
  284. X        typeset(getuval(3, fp), TRUE, magval);
  285. X    Case SET4: 
  286. X        typeset(getsval(4, fp), TRUE, magval);
  287. X
  288. X        // just typeset a character
  289. X    Case PUT1: 
  290. X        typeset(getuval(1, fp), FALSE, magval);
  291. X    Case PUT2: 
  292. X        typeset(getuval(2, fp), FALSE, magval);
  293. X    Case PUT3: 
  294. X        typeset(getuval(3, fp), FALSE, magval);
  295. X    Case PUT4: 
  296. X        typeset(getsval(4, fp), FALSE, magval);
  297. X
  298. X        // print a rule
  299. X    Case SETRULE: 
  300. X        typerule(fp, TRUE, magval);
  301. X    Case PUTRULE: 
  302. X        typerule(fp, FALSE, magval);
  303. X
  304. X    Case NOOP: 
  305. X
  306. X    Case PUSH: 
  307. X        pushdvi();
  308. X    Case POP: 
  309. X        popdvi();
  310. X
  311. X        // horizontal moves (negative == move left)
  312. X    Case RIGHT1: 
  313. X        moveright(Getsval(1, fp) * magval);
  314. X    Case RIGHT2: 
  315. X        moveright(Getsval(2, fp) * magval);
  316. X    Case RIGHT3: 
  317. X        moveright(Getsval(3, fp) * magval);
  318. X    Case RIGHT4: 
  319. X        moveright(Getsval(4, fp) * magval);
  320. X
  321. X        // move horizontal based on the var W
  322. X    Case W0: 
  323. X        moveright(W);
  324. X    Case W1: 
  325. X        moveright(W = Getsval(1, fp) * magval);
  326. X    Case W2: 
  327. X        moveright(W = Getsval(2, fp) * magval);
  328. X    Case W3: 
  329. X        moveright(W = Getsval(3, fp) * magval);
  330. X    Case W4: 
  331. X        moveright(W = Getsval(4, fp) * magval);
  332. X
  333. X        // move horizontal based on the var X
  334. X    Case X0: 
  335. X        moveright(X);
  336. X    Case X1: 
  337. X        moveright(X = Getsval(1, fp) * magval);
  338. X    Case X2: 
  339. X        moveright(X = Getsval(2, fp) * magval);
  340. X    Case X3: 
  341. X        moveright(X = Getsval(3, fp) * magval);
  342. X    Case X4: 
  343. X        moveright(X = Getsval(4, fp) * magval);
  344. X
  345. X        // move vertically (negative == towards top of page)
  346. X    Case DOWN1: 
  347. X        movedown(Getsval(1, fp) * magval);
  348. X    Case DOWN2: 
  349. X        movedown(Getsval(2, fp) * magval);
  350. X    Case DOWN3: 
  351. X        movedown(Getsval(3, fp) * magval);
  352. X    Case DOWN4: 
  353. X        movedown(Getsval(4, fp) * magval);
  354. X
  355. X        // move vertically based on the var Y
  356. X    Case Y0: 
  357. X        movedown(Y);
  358. X    Case Y1: 
  359. X        movedown(Y = Getsval(1, fp) * magval);
  360. X    Case Y2: 
  361. X        movedown(Y = Getsval(2, fp) * magval);
  362. X    Case Y3: 
  363. X        movedown(Y = Getsval(3, fp) * magval);
  364. X    Case Y4: 
  365. X        movedown(Y = Getsval(4, fp) * magval);
  366. X
  367. X        // move vertically based on the var Z
  368. X    Case Z0: 
  369. X        movedown(Z);
  370. X    Case Z1: 
  371. X        movedown(Z = Getsval(1, fp) * magval);
  372. X    Case Z2: 
  373. X        movedown(Z = Getsval(2, fp) * magval);
  374. X    Case Z3: 
  375. X        movedown(Z = Getsval(3, fp) * magval);
  376. X    Case Z4: 
  377. X        movedown(Z = Getsval(4, fp) * magval);
  378. X
  379. X        // change current font
  380. X    Case FNT1: 
  381. X        newfont(getuval(1, fp));
  382. X    Case FNT2: 
  383. X        newfont(getuval(2, fp));
  384. X    Case FNT3: 
  385. X        newfont(getuval(3, fp));
  386. X    Case FNT4: 
  387. X        newfont(getsval(4, fp));
  388. X
  389. X        // special - used definable
  390. X    Case XXX1: 
  391. X        special(fp, getuval(1, fp));
  392. X    Case XXX2: 
  393. X        special(fp, getuval(2, fp));
  394. X    Case XXX3: 
  395. X        special(fp, getuval(3, fp));
  396. X    Case XXX4: 
  397. X        special(fp, getsval(4, fp));
  398. X
  399. X        // define a font - note that this will be a redefinition
  400. X    Case FNTDEF1: 
  401. X        definefont(fp, getuval(1, fp), mag);
  402. X    Case FNTDEF2: 
  403. X        definefont(fp, getuval(2, fp), mag);
  404. X    Case FNTDEF3: 
  405. X        definefont(fp, getuval(3, fp), mag);
  406. X    Case FNTDEF4: 
  407. X        definefont(fp, getsval(4, fp), mag);
  408. X
  409. X    Default: 
  410. X        quit("Unexpected opcode %d", opcode);
  411. X    }
  412. X    }
  413. }
  414. X
  415. X
  416. // read the DVI file and create a list with pointers to every
  417. // page in the file - also calculate a section number for each page
  418. //
  419. static void loadpages(FILE *fp, long pageloc, long numpages, 
  420. X        long §ions, Pageinfo &pages)
  421. {
  422. X    long loc = pageloc;
  423. X    long lastpage = MAXLONG;
  424. X    long i;
  425. X
  426. X    sections = 1;
  427. X
  428. X    // search backwards through the DVI file
  429. X    for (i = numpages - 1; loc >= 0 && i >= 0; i--)
  430. X    {
  431. X    (void)fseek(fp, loc, SEEK_SET);
  432. X    if (getuval(1, fp) != BOP)
  433. X        quit("Expected BOP");
  434. X
  435. X    // get the values of the internal TeX variables
  436. X    // - the first is a page number (c[0])
  437. X    long c[10];
  438. X    for (int j = 0; j < 10; j++)
  439. X        c[j] = getsval(4, fp);
  440. X    loc = getsval(4, fp);    // location of previous page in file
  441. X
  442. X    // new section if we see a page larger than the previous one
  443. X    if (c[0] >= lastpage)
  444. X        sections++;
  445. X    lastpage = c[0];
  446. X
  447. X    // save the "real" page number and the offset in the file
  448. X    pages[i].page = c[0];
  449. X    pages[i].section = sections;
  450. X    pages[i].loc = ftell(fp);
  451. X    }
  452. X
  453. X    // now change the section numbers to be in the proper order
  454. X    for (i = 0; i < numpages; i++)
  455. X    pages[i].section = sections - pages[i].section + 1;
  456. }
  457. X
  458. X
  459. // dump only the specified pages from the DVI file
  460. //
  461. static void dumppages(FILE *fp, Pagespec &pages, 
  462. X            Pageinfo &allpages, long sections)
  463. {
  464. X    long numpages = allpages.size();
  465. X
  466. X    for (int i = 0; i < pages.size(); i++)
  467. X    {
  468. X    // get the page spec entry in normal or reverse order
  469. X    long pent = reverse ? pages.size() - i - 1 : i;
  470. X
  471. X    // if the end is not specified, take the current maximum
  472. X    long endsect = pages[pent].endsection == MAXLONG ? sections
  473. X        : pages[pent].endsection;
  474. X    long endpage = pages[pent].endpage == MAXLONG ? numpages
  475. X        : pages[pent].endpage;
  476. X
  477. X    // print only the last section? make sure we go through loop once
  478. X    long startsect = pages[pent].section;
  479. X    if (startsect == MAXLONG)
  480. X        startsect = endsect;
  481. X
  482. X    for (long s = startsect; s <= endsect; s++)
  483. X    {
  484. X        long snum = reverse ? endsect - s + startsect : s;
  485. X        for (long p = pages[pent].page; p <= endpage; p++)
  486. X        {
  487. X        long pnum = reverse ? endpage - p + pages[pent].page : p;
  488. X
  489. X        // look for this page/section in the list of allpages
  490. X        // - if section == MAXLONG - 1, then use the last section
  491. X        long ent;
  492. X        for (ent = numpages - 1; ent >= 0; ent--)
  493. X            if (allpages[ent].page == pnum
  494. X                && allpages[ent].section == snum)
  495. X            break;
  496. X
  497. X        if (ent < 0)
  498. X        {
  499. X            // print an error only if the user explicitly specified
  500. X            // a page that does not exist - do not print an error
  501. X            // if we are going through to the end
  502. X            if (pages[pent].section == MAXLONG
  503. X                || pages[pent].endsection <= pages[pent].section)
  504. X            if (pages[pent].endpage == MAXLONG
  505. X                || pages[pent].endpage < pages[pent].page)
  506. X                if (pages[pent].section <= sections)
  507. X                continue;
  508. X
  509. X            error("No page/section %ld.%ld in DVI file", pnum, snum);
  510. X            continue;
  511. X        }
  512. X
  513. X        // seek to that page and spit it out
  514. X        (void)fseek(fp, allpages[ent].loc, SEEK_SET);
  515. X        mesg(" [%ld.%ld", allpages[ent].page, allpages[ent].section);
  516. X        debug(1, "Page: %ld.%ld (%ld)", allpages[ent].page,
  517. X            allpages[ent].section, ent + 1);
  518. X        dopage(fp, allpages[ent].page);
  519. X        mesg("]");
  520. X        }
  521. X    }
  522. X    }
  523. }
  524. X
  525. X
  526. // dump all the pages in the DVI file in either forward or reverse order
  527. //
  528. static void dumpall(FILE *fp, Pageinfo &allpages)
  529. {
  530. X    long numpages = allpages.size();
  531. X    for (int i = 0; i < numpages; i++)
  532. X    {
  533. X    long p = reverse ? numpages - i - 1 : i;
  534. X    (void)fseek(fp, allpages[p].loc, SEEK_SET);
  535. X    mesg(" [%ld.%ld", allpages[p].page, allpages[p].section);
  536. X    debug(1, "Page: %ld.%ld (%ld)", allpages[p].page,
  537. X        allpages[p].section, p + 1);
  538. X    dopage(fp, allpages[p].page);
  539. X    mesg("]");
  540. X    }
  541. }
  542. X
  543. X
  544. // process the DVI file "fp" - verify the file, setup the fonts, then
  545. // print pages in the file either backwards or forwards - print only
  546. // that "pages" specified, or everything if none were specified
  547. // 
  548. void dodvi(FILE *fp, Pagespec &pages)
  549. {
  550. X    // verify the preamble and id value
  551. X    if (getuval(1, fp) != PRE)
  552. X    quit("Not a DVI file");
  553. X    long version = getuval(1, fp);
  554. X    if (version != ID)
  555. X    {
  556. X    debug(7, "DVI file version = %ld instead of %d", version, ID);
  557. X    quit("Incorrect DVI file version");
  558. X    }
  559. X
  560. X    // if we cannot seek, then we cannot do anything
  561. X    if (fseek(fp, 0, SEEK_END) != 0)
  562. X    quit("Cannot seek to end of DVI file");
  563. X
  564. X    long floc = ftell(fp);
  565. X    debug(2, "DVI file len = %ld", floc);
  566. X
  567. X    // now look for the real end of the DVI file (after the POSTPOST)
  568. X    register int opcode = FILLER;
  569. X    while (opcode == FILLER && floc > 0)
  570. X    {
  571. X    (void)fseek(fp, --floc, SEEK_SET);
  572. X    opcode = (int)getuval(1, fp);
  573. X    }
  574. X    if (opcode != ID)
  575. X    {
  576. X    debug(7, "DVI file version = %d instead of %d", opcode, ID);
  577. X    quit("Incorrect DVI file version");
  578. X    }
  579. X
  580. X    // get the pointer to the start of the postamble
  581. X    (void)fseek(fp, floc -= 4, SEEK_SET);
  582. X    long postloc = getuval(4, fp);
  583. X    (void)fseek(fp, postloc, SEEK_SET);
  584. X
  585. X    // verify that we are where we think we are
  586. X    if (getuval(1, fp) != POST)
  587. X    quit("Expected POST");
  588. X
  589. X    // pointer to the last page in the DVI file
  590. X    long pageloc = getsval(4, fp);
  591. X
  592. X    // read in the other values in the postamble
  593. X    double numerator = Getsval(4, fp);
  594. X    if (numerator <= 0)
  595. X    quit("Illegal numerator");
  596. X
  597. X    double denominator = Getsval(4, fp);
  598. X    if (denominator <= 0)
  599. X    quit("Illegal denominator");
  600. X
  601. X    mag = getsval(4, fp);
  602. X    if (usermag > 0)
  603. X    mag = usermag;
  604. X    magval = (double)mag;
  605. X    if (mag <= 0)
  606. X    quit("Illegal magnification");
  607. X    magval *= numerator / denominator / 25400000.0 * 473628672.0 / 1000.0;
  608. X    debug(3, "num=%f denom=%f mag=%ld/%f", numerator, denominator,
  609. X        mag, magval);
  610. X
  611. X    // worst-case page sizes - we ignore these for now
  612. X    long tallest = getsval(4, fp);
  613. X    long widest = getsval(4, fp);
  614. X    long maxdepth = getsval(2, fp);
  615. X    long numpages = getuval(2, fp);
  616. X    debug(3, "tallest=%ld widest=%ld maxdepth=%ld", tallest, widest, maxdepth);
  617. X    debug(1, "numpages=%ld", numpages);
  618. X
  619. X    // scan the opcodes in the rest of the postamble - only font
  620. X    // definitions and specials are allowed here
  621. X    while ((opcode = (int)getuval(1, fp)) != POSTPOST)
  622. X    switch (opcode)
  623. X    {
  624. X    Case FNTDEF1: 
  625. X        definefont(fp, getuval(1, fp), mag);
  626. X    Case FNTDEF2: 
  627. X        definefont(fp, getuval(2, fp), mag);
  628. X    Case FNTDEF3: 
  629. X        definefont(fp, getuval(3, fp), mag);
  630. X    Case FNTDEF4: 
  631. X        definefont(fp, getsval(4, fp), mag);
  632. X
  633. X    Case XXX1: 
  634. X        special(fp, getuval(1, fp));
  635. X    Case XXX2: 
  636. X        special(fp, getuval(2, fp));
  637. X    Case XXX3: 
  638. X        special(fp, getuval(3, fp));
  639. X    Case XXX4: 
  640. X        special(fp, getsval(4, fp));
  641. X
  642. X    Case NOOP: 
  643. X
  644. X    Default: 
  645. X        quit("Illegal opcode = %d in font definitions", opcode);
  646. X    }
  647. X
  648. X    // initialize the page pointer table
  649. X    Pageinfo allpages(numpages);
  650. X    long sections;
  651. X    loadpages(fp, pageloc, numpages, sections, allpages);
  652. X
  653. X    // process the pages as specified
  654. X    if (pages.size() < 1)
  655. X    dumpall(fp, allpages);
  656. X    else
  657. X    dumppages(fp, pages, allpages, sections);
  658. X
  659. X    mesg(NULL);
  660. }
  661. SHAR_EOF
  662. chmod 0444 dvi.C ||
  663. echo 'restore of dvi.C failed'
  664. Wc_c="`wc -c < 'dvi.C'`"
  665. test 11617 -eq "$Wc_c" ||
  666.     echo 'dvi.C: original size 11617, current size' "$Wc_c"
  667. fi
  668. # ============= font.C ==============
  669. if test -f 'font.C' -a X"$1" != X"-c"; then
  670.     echo 'x - skipping font.C (File already exists)'
  671. else
  672. echo 'x - extracting font.C (Text)'
  673. sed 's/^X//' << 'SHAR_EOF' > 'font.C' &&
  674. // Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
  675. static const char rcsid[] = "$Header: font.C,v 1.42 91/04/02 17:59:01 hmgr Exp $";
  676. X
  677. // font manipulation and basic typesetting functions
  678. //
  679. // by Parag Patel
  680. X
  681. #include "defs.h"
  682. X
  683. X
  684. // local globals
  685. static int fontsonpage;            // # of fonts on current page
  686. static long devv;            // current device Vertical coord
  687. static long devh;            // Horizontal coord (both in pixels)
  688. static font *devfont;            // current font in device
  689. X
  690. X
  691. font::font()
  692. {
  693. X    chr = new fontchar[MAXCHARS];
  694. X    // this initialization is redundant, but safer
  695. X    fp = NULL;
  696. X    use = 0;
  697. X    path = basename = NULL;
  698. X    onpage = toomany = downloaded = setup = NULL;
  699. }
  700. X
  701. font::~font()
  702. {
  703. X    if (fp != NULL)
  704. X    fclose(fp);
  705. X    delete[MAXCHARS] chr;
  706. }
  707. X
  708. // return the fontlist location for the font number specified
  709. // - returns one more than the current size if there is no such font
  710. static long getfontloc(long fnum)
  711. {
  712. X    for (long f = 0; f < fontlist.size(); f++)
  713. X    if (fontlist[f] != NULL && fontlist[f]->num == fnum)
  714. X        break;
  715. X    return f;
  716. }
  717. X
  718. // clear font info for a new page - there are currently no fonts on
  719. // this page - reset the device coordinates to "unknown" - there is no
  720. // current font selected, nor a current font in the device
  721. // 
  722. void clearfonts()
  723. {
  724. X    for (int i = 0; i < fontlist.size(); i++)
  725. X    if (fontlist[i] != NULL)
  726. X        fontlist[i]->toomany = fontlist[i]->onpage = FALSE;
  727. X    fontsonpage = 0;
  728. X    devh = devv = -MAXLONG;
  729. X    currfont = devfont = NULL;
  730. }
  731. X
  732. X
  733. static void setupbits(font &f)
  734. {
  735. X    static long minm = MAXLONG;
  736. X    static long maxm = -MAXLONG;
  737. X    static long minn = MAXLONG;
  738. X    static long maxn = -MAXLONG;
  739. X
  740. X    if (f.minm >= minm && f.maxm <= maxm
  741. X        && f.minn >= minn && f.maxn <= maxn)
  742. X    return;
  743. X
  744. X    if (fontbits != NULL)
  745. X    {
  746. X    for (long i = maxn - minn; i >= 0; i--)
  747. X        delete fontbits[i];
  748. X    delete fontbits;
  749. X    }
  750. X
  751. X    if (f.maxm > maxm)
  752. X    maxm = f.maxm + 10;
  753. X    if (f.minm < minm)
  754. X    minm = f.minm - 10;
  755. X    if (f.maxn > maxn)
  756. X    maxn = f.maxn + 10;
  757. X    if (f.minn < minn)
  758. X    minn = f.minn - 10;
  759. X
  760. X    debug(4, "newbits maxm=%ld minm=%ld  maxn=%ld minn=%ld",
  761. X        maxm, minm, maxn, minn);
  762. X
  763. X    // allocate the memory that we will need
  764. X    fontbits = new Bitvec *[maxn - minn + 2];
  765. X    for (long i = maxn - minn; i >= 0; i--)
  766. X    fontbits[i] = new Bitvec(maxm - minm + 2);
  767. }
  768. X
  769. X
  770. // define a font "fnum" from the file "fp" at the magnification "mag"
  771. // - "fp" is a pointer into a DVI file right after the FNTDEF byte
  772. // - this function will be called twice for each font - once in the
  773. // postamble and once just before it is used (if it is used)
  774. // 
  775. void definefont(FILE *fp, long fnum, long mag)
  776. {
  777. X    // find the font with this number in our fontlist
  778. X    long floc = getfontloc(fnum);
  779. X
  780. X    // if already loaded, then we are not in the postamble anymore
  781. X    boolean loaded = (fontlist[floc] != NULL);
  782. X
  783. X    debug(2, "fontnum = %ld(%ld)%s", fnum, floc, loaded ? " loaded" : "");
  784. X
  785. X    // allocate space for this font, if necessary
  786. X    if (!loaded)
  787. X    fontlist[floc] = new font;
  788. X
  789. X    font &f = *fontlist[floc].ptr;
  790. X
  791. X    if (loaded)
  792. X    {
  793. X    // ignore the values in the file - we already have them
  794. X    (void)getsval(4, fp);
  795. X    (void)getsval(4, fp);
  796. X    (void)getsval(4, fp);
  797. X    skipbytes(getuval(1, fp) + getuval(1, fp), fp);
  798. X    return;
  799. X    }
  800. X
  801. X    // initialize the font and start reading the values out of the file
  802. X    f.fp = NULL;
  803. X    f.use = 0;
  804. X    f.num = fnum;
  805. X    f.checksum = getsval(4, fp);
  806. X    f.scaledsize = getsval(4, fp);
  807. X    f.designsize = getsval(4, fp);
  808. X    debug(3, "checksum=%ld scaled=%ld design=%ld",
  809. X        f.checksum, f.scaledsize, f.designsize);
  810. X
  811. X    f.mag = (long)((double)mag * (double)f.scaledsize /
  812. X                                    (double)f.designsize + 0.5);
  813. X
  814. X    // get the name of the font file - if the library name length
  815. X    // (liblen) is 0, then use the default library directory instead
  816. X
  817. X    int liblen = (int)getuval(1, fp);
  818. X    int namelen = (int)getuval(1, fp);
  819. X
  820. X    f.path = NULL;
  821. X    f.basename = new char[namelen + 1];
  822. X    int i;
  823. X
  824. X    // read the optional font directory name from the DVI file
  825. X    if (liblen != 0)
  826. X    {
  827. X    // just use what the DVI file has
  828. X    char *s = f.path = new char[liblen + 1];
  829. X    for (i = 0; i < liblen; i++)
  830. X        *s++ = (unsigned char)getuval(1, fp);
  831. X    *s = '\0';
  832. X    }
  833. X
  834. X    // get the name of the font file to load
  835. X    char *s = f.basename;
  836. X    for (i = 0; i < namelen; i++)
  837. X    *s++ = (unsigned char)getuval(1, fp);
  838. X    *s = '\0';
  839. X    debug(4, "libname=%s  basename=%s", 
  840. X        f.path == NULL ? "" : f.path, f.basename);
  841. X
  842. X    // just defined - not yet downloaded - not setup
  843. X    f.setup = f.downloaded = f.onpage = f.toomany = FALSE;
  844. X
  845. X    // no characters are downloaded either
  846. X    for (i = 0; i < MAXCHARS; i++)
  847. X    f.chr[i].downloaded = f.chr[i].charbig = FALSE;
  848. }
  849. X
  850. X
  851. // change to a new font "fnum" - this is the FNT DVI command
  852. // 
  853. void newfont(long fnum)
  854. {
  855. X    long f = getfontloc(fnum);
  856. X    debug(5, "Change to font %ld(%ld)", fnum, f);
  857. X
  858. X    currfont = fontlist[f];
  859. X    if (currfont == NULL)
  860. X    quit("Font %ld(%ld) has not been defined yet", fnum, f);
  861. }
  862. X
  863. X
  864. // move the device's cursor to the current H and V values
  865. // 
  866. void makecurrent(boolean force)
  867. {
  868. X    long h = dev_sp2dev(H);
  869. X    long v = dev_sp2dev(V);
  870. X
  871. X    // use the most efficient move that we can
  872. X    if (force || (devh != h && devv != v))
  873. X    dev_movehv(h, v);
  874. X    else if (devh != h)
  875. X    dev_moveh(h);
  876. X    else if (devv != v)
  877. X    dev_movev(v);
  878. X
  879. X    debug(8, "lastH=%ld lastV=%ld  H=%ld V=%ld", devh, devv, h, v);
  880. X
  881. X    // update the current cursor values
  882. X    devh = h;
  883. X    devv = v;
  884. }
  885. X
  886. X
  887. static void dumpescape(const char *s, long len)
  888. {
  889. X    for (long i = 0; i < len; s++, i++)
  890. X    {
  891. X    if (*s != '\\' && *s != '`')
  892. X    {
  893. X        putchar(*s);
  894. X        continue;
  895. X    }
  896. X    s++;
  897. X    i++;
  898. X    if (i >= len)
  899. X        break;
  900. X
  901. X    if (isdigit(*s))
  902. X    {
  903. X        int chr = *s - '0';
  904. X        int base = 8;
  905. X        if (*s == '0')
  906. X        {
  907. X        s++;
  908. X        i++;
  909. X        switch (isupper(*s) ? tolower(*s) : *s)
  910. X        {
  911. X        Case 'b': 
  912. X            base = 2;
  913. X        Case 'o': 
  914. X            base = 8;
  915. X        Case 'd': 
  916. X            base = 10;
  917. X        Case 'x': 
  918. X            base = 16;
  919. X        Default: 
  920. X            s--;
  921. X            i--;
  922. X        }
  923. X        }
  924. X        s++;
  925. X        i++;
  926. X        for (; isxdigit(*s) && i < len; s++, i++)
  927. X        {
  928. X        int d = (islower(*s) ? toupper(*s) : *s)
  929. X            - (isdigit(*s) ? '0' : 'A' - 10);
  930. X        if (d >= base)
  931. X            break;
  932. X        chr = (chr * base) + d;
  933. X        }
  934. X        s--;
  935. X        i--;
  936. X        putchar(chr);
  937. X        continue;
  938. X    }
  939. X
  940. X    switch (isupper(*s) ? tolower(*s) : *s)
  941. X    {
  942. X    Case 'b': 
  943. X        putchar('\b');
  944. X    Case 'f': 
  945. X        putchar('\f');
  946. X    Case 'n': 
  947. X        putchar('\n');
  948. X    Case 'r': 
  949. X        putchar('\r');
  950. X    Case 't': 
  951. X        putchar('\t');
  952. X    Case 'v': 
  953. X        putchar('\v');
  954. X    Case '\\': 
  955. X        putchar('\\');
  956. X    Case '`': 
  957. X        putchar('`');
  958. X    Case 'e': 
  959. X        putchar('\033');
  960. X    Case '?': 
  961. X        putchar('\177');
  962. X    Case '^': 
  963. X        s++;
  964. X        i++;
  965. X        putchar(*s == '?' ? '\177' : (*s & 037));
  966. X    Default: 
  967. X        // putchar('\\');
  968. X        putchar(*s);
  969. X    }
  970. X    }
  971. }
  972. X
  973. // DVI XXX special command - "num" is the number of bytes in the DVI
  974. //      file that are for the special command
  975. // take the special string as a file name of a raw device-specific
  976. // image file and dump it straight to the device
  977. // 
  978. void special(FILE *fp, long num)
  979. {
  980. X    debug(2, "special length = %ld", num);
  981. X
  982. X    // allocate a buffer that is large enough for this length
  983. X    static char *buf = NULL;
  984. X    static long blen = 0;
  985. X    if (num >= blen)
  986. X    {
  987. X    if (buf != NULL)
  988. X        delete buf;
  989. X    buf = new char[blen = num + 1];
  990. X    }
  991. X
  992. X    // read in the data from the DVI file into our buffer
  993. X    char *s = buf;
  994. X    for (long i = num; i-- > 0;)
  995. X    *s++ = (unsigned char)getuval(1, fp);
  996. X    *s = '\0';
  997. X
  998. X    // we use the first word (up to a space) for identifying different
  999. X    // kinds of special files
  1000. X    enum Specials
  1001. X    {
  1002. X    S_NONE = 0,
  1003. X    S_RASTERFILE,
  1004. X    S_ESCAPESEQ,
  1005. X    S_RAWSTRING,
  1006. X    } type;
  1007. X
  1008. X    // handle special escape-sequences
  1009. X    if (strncmp("escapeseq ", buf, 10) == 0)
  1010. X    {
  1011. X    s = buf + 10;
  1012. X    num -= 10;
  1013. X    type = S_ESCAPESEQ;
  1014. X    debug(4, "Special == escapeseq = %s", s);
  1015. X    mesg(" <<escapeseq");
  1016. X    makecurrent();
  1017. X    dev_push();
  1018. X    dumpescape(s, num);
  1019. X    dev_pop();
  1020. X    mesg(">>");
  1021. X    return;
  1022. X    }
  1023. X
  1024. X    // handle special raw-strings
  1025. X    if (strncmp("rawstring ", buf, 10) == 0)
  1026. X    {
  1027. X    s = buf + 10;
  1028. X    num -= 10;
  1029. X    type = S_RAWSTRING;
  1030. X    debug(4, "Special == rawstring = %s", s);
  1031. X    mesg(" <<rawstring");
  1032. X    makecurrent();
  1033. X    dev_push();
  1034. X    while (num-- > 0)
  1035. X        putchar(*s++);
  1036. X    dev_pop();
  1037. X    mesg(">>");
  1038. X    return;
  1039. X    }
  1040. X
  1041. X    // handle raw file dumps - usually graphics data
  1042. X    if (strncmp("rasterfile ", buf, 11) == 0)
  1043. X    {
  1044. X    s = buf + 11;
  1045. X    type = S_RASTERFILE;
  1046. X    }
  1047. X    else if (strncmp("pcl:", buf, 4) == 0)
  1048. X    {
  1049. X    s = buf + 4;
  1050. X    type = S_RASTERFILE;
  1051. X    }
  1052. X    else
  1053. X    s = buf;
  1054. X
  1055. X    debug(4, "Special == rasterfile = %s", s);
  1056. X    mesg(" <%s", s);
  1057. X
  1058. X    // now open this file and dump it to the device
  1059. X
  1060. X    FILE *sp = fopenp(dviinput, s, F_READ);
  1061. X    if (sp == NULL)
  1062. X    quit("Cannot open \"%s\" for reading", s);
  1063. X
  1064. X    // move the cursor, and save the current location in the device
  1065. X    makecurrent();
  1066. X    dev_push();
  1067. X
  1068. X    // dump the file
  1069. X    int l;
  1070. X    char dat[1024];
  1071. X    while ((l = fread(dat, sizeof *dat, sizeof dat, sp)) > 0)
  1072. X    fwrite(dat, sizeof *dat, l, stdout);
  1073. X
  1074. X    fclose(sp);
  1075. X
  1076. X    // restore the cursor
  1077. X    dev_pop();
  1078. X    mesg(">");
  1079. }
  1080. X
  1081. X
  1082. // change the current font that is downloaded to the device if we have
  1083. // to - this is completely demand-driven - a font is never even read into
  1084. // memory much less downloaded unless a character from it is actually
  1085. // going to be printed
  1086. // 
  1087. static void changefont()
  1088. {
  1089. X    // do we need to download this font?
  1090. X    if (!currfont->downloaded)
  1091. X    {
  1092. X    mesg(" (");
  1093. X
  1094. X    if (!currfont->setup)
  1095. X    {
  1096. X        // load in the font info - we're really going to use it
  1097. X        setupfont(*currfont);
  1098. X        setupbits(*currfont);
  1099. X        currfont->setup = TRUE;
  1100. X    }
  1101. X    mesg("%s", currfont->basename);
  1102. X
  1103. X    static int fontsdown = 0;
  1104. X    currfont->use++;
  1105. X
  1106. X    if (fontsdown < MAXLOADED)
  1107. X        fontsdown++;
  1108. X    else
  1109. X    {
  1110. X        // we need to delete a font from the device
  1111. X        register int i;
  1112. X        int fn = -1;
  1113. X        long u = MAXLONG;
  1114. X
  1115. X        // find the least recently used font
  1116. X        for (i = 0; i < fontlist.size(); i++)
  1117. X        if (fontlist[i] != NULL && fontlist[i]->downloaded
  1118. X            && !fontlist[i]->onpage && fontlist[i]->use < u)
  1119. X        {
  1120. X            fn = i;
  1121. X            u = fontlist[i]->use;
  1122. X        }
  1123. X
  1124. X        // we need too many fonts - dump currfont in graphics mode
  1125. X        if (fn < 0)
  1126. X        {
  1127. X        currfont->toomany = TRUE;
  1128. X        mesg("#)");
  1129. X        return;
  1130. X        }
  1131. X
  1132. X        // mark it as not downloaded, then delete it
  1133. X        font &f = *fontlist[fn].ptr;
  1134. X        for (i = 0; i < MAXCHARS; i++)
  1135. X        f.chr[i].downloaded = FALSE;
  1136. X        f.toomany = f.downloaded = FALSE;
  1137. X        dev_delfont(f);
  1138. X    }
  1139. X
  1140. X    // downloaded this font
  1141. X    dev_newfont(*currfont);
  1142. X    currfont->downloaded = TRUE;
  1143. X
  1144. X    mesg(")");
  1145. X    }
  1146. X
  1147. X    // select this font in the device
  1148. X    dev_usefont(*currfont);
  1149. X    devfont = currfont;
  1150. X
  1151. X    // if this font is already being used on page, we are done
  1152. X    if (currfont->onpage || currfont->toomany)
  1153. X    return;
  1154. X    currfont->onpage = TRUE;
  1155. X
  1156. X    // are there too many fonts on this page?  if so, mark
  1157. X    // the font as toomany to print it in graphics mode
  1158. X    if (++fontsonpage > MAXONPAGE)
  1159. X    {
  1160. X    debug(3, "too many fonts on page - currfont marked");
  1161. X    currfont->toomany = TRUE;
  1162. X    mesg("#");
  1163. X    }
  1164. }
  1165. X
  1166. X
  1167. // typeset a character - this is the DVI SET or PUT command - if "move"
  1168. // is TRUE, then the cursor will be moved right by the width of the
  1169. // character
  1170. //
  1171. void typeset(long ch, boolean move, double magval)
  1172. {
  1173. X    fontchar & gch = currfont->chr[ch];
  1174. X
  1175. X    // change the font if we have to
  1176. X    if (currfont != devfont)
  1177. X    changefont();
  1178. X
  1179. X    // download the character if we have to - this also gets bigchars
  1180. X    if (!gch.downloaded || gch.charbig || currfont->toomany)
  1181. X    downchar((int)ch, currfont->toomany);
  1182. X
  1183. X    // print the character if it is not too big
  1184. X    if (!gch.charbig && !currfont->toomany)
  1185. X    {
  1186. X    makecurrent();
  1187. X    int len;
  1188. X    const char *dat = dev_char2dev((int)ch, len);
  1189. X    fwrite(dat, sizeof *dat, len, stdout);
  1190. X    devh += gch.dx >> 16;
  1191. X    }
  1192. X
  1193. X    if (move)
  1194. X    moveright(gch.width * magval);
  1195. }
  1196. X
  1197. X
  1198. // DVI SETRULE or PUTRULE command - again, if "move" is TRUE, then the
  1199. // cursor is moved to the right, else it isn't
  1200. // 
  1201. void typerule(FILE *fp, boolean move, double magval)
  1202. {
  1203. X    double a = Getsval(4, fp) * magval;
  1204. X    double b = Getsval(4, fp) * magval;
  1205. X
  1206. X    // let the device do the work (if it can)
  1207. X    if (a > 0 && b > 0)
  1208. X    dev_rule(a, b);
  1209. X
  1210. X    if (move)
  1211. X    moveright(b);
  1212. }
  1213. SHAR_EOF
  1214. chmod 0444 font.C ||
  1215. echo 'restore of font.C failed'
  1216. Wc_c="`wc -c < 'font.C'`"
  1217. test 12300 -eq "$Wc_c" ||
  1218.     echo 'font.C: original size 12300, current size' "$Wc_c"
  1219. fi
  1220. # ============= readfont.C ==============
  1221. if test -f 'readfont.C' -a X"$1" != X"-c"; then
  1222.     echo 'x - skipping readfont.C (File already exists)'
  1223. else
  1224. echo 'x - extracting readfont.C (Text)'
  1225. sed 's/^X//' << 'SHAR_EOF' > 'readfont.C' &&
  1226. // Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
  1227. static const char rcsid[] = "$Header: readfont.C,v 1.21 91/04/02 17:50:26 hmgr Exp $";
  1228. X
  1229. // read font data from the METAFONT GF (generic font) files
  1230. //
  1231. // by Parag Patel
  1232. X
  1233. #include "defs.h"
  1234. X
  1235. X
  1236. // maximum number of file that we can keep open at one time - we try to
  1237. // keep as many font files open at one time as we can instead of
  1238. // reading the entire font into memory - this should gain a little
  1239. // speed if only a few characters are loaded from many different fonts
  1240. // (which is the normal case)
  1241. //
  1242. #ifdef _SC_OPEN_MAX
  1243. const long MAXFILES = sysconf(_SC_OPEN_MAX) - NUMOPENFILES;
  1244. #else
  1245. const long MAXFILES = _NFILE - NUMOPENFILES;
  1246. #endif
  1247. X
  1248. static int numfiles = 0;        // number of files currently open
  1249. X
  1250. X
  1251. // try looking for a particular type of font file - this is called 
  1252. // multiple times until we succeeding in finding a font we can use
  1253. //
  1254. static int tryfile(font &f, char *dir, char *mag, char *base, char *ext)
  1255. {
  1256. X    static char buf[MAXPATHLEN + 1];
  1257. X    sprintf(buf, "%s/%s/%s%s", dir, mag, base, ext);
  1258. X    char *path = buf;
  1259. X    FILE *fp = fopen(path, F_READ);
  1260. X    if (fp == NULL)
  1261. X    return FALSE;
  1262. X
  1263. X    // first byte is a preamble byte - same for GF and PK files
  1264. X    if (getuval(1, fp) != FPRE)
  1265. X    {
  1266. X    fclose(fp);
  1267. X    return FALSE;
  1268. X    }
  1269. X
  1270. X    // second byte is the font version ID field
  1271. X    f.type = (int)getuval(1, fp);
  1272. X    char *old = f.path;
  1273. X    f.path = path;
  1274. X    switch (f.type)
  1275. X    {
  1276. X    Case GFID:
  1277. X    debug(2, "GF font file %s", path);
  1278. X    setupgffont(f, fp);
  1279. X    Case PKID:
  1280. X    debug(2, "PK font file %s", path);
  1281. X    setuppkfont(f, fp);
  1282. X    Default:
  1283. X    fclose(fp);
  1284. X    f.path = old;
  1285. X    return FALSE;
  1286. X    }
  1287. X
  1288. X    delete old;
  1289. X    f.path = strdup(path);
  1290. X    old = f.basename;
  1291. X    sprintf(buf, "%s/%s%s", mag, base, ext);
  1292. X    f.basename = strdup(buf);
  1293. X    delete old;
  1294. X    debug(6, "font basename = %s", f.basename);
  1295. X
  1296. X    // keep only a MAXFILES number of font files open at one time
  1297. X    if (numfiles >= MAXFILES)
  1298. X    {
  1299. X    fclose(fp);
  1300. X    f.fp = NULL;
  1301. X    }
  1302. X    else
  1303. X    {
  1304. X    f.fp = fp;
  1305. X    numfiles++;
  1306. X    }
  1307. X
  1308. X    return TRUE;
  1309. }
  1310. X
  1311. X
  1312. // setup a new font in memory - the font is already initialized with
  1313. // the information from the DVI file - we now have to actually read the
  1314. // font file (GF or PK) to get the rest of the font's description
  1315. // 
  1316. void setupfont(font &f)
  1317. {
  1318. X    if (f.path != NULL)
  1319. X    if (tryfile(f, f.path, "", f.basename, ""))
  1320. X        return;
  1321. X
  1322. X    // setup the font directory cache if we need to
  1323. X    if (pathlist.size() < 1)
  1324. X    setupdirs(fontpath);
  1325. X
  1326. X    for (int i = 0; i < pathlist.size(); i++)
  1327. X    {
  1328. X    Pathent & p = pathlist[i];
  1329. X
  1330. X    if (tryfile(f, p.path, pkmagdir(p.dirs, f.mag), f.basename, ".pk"))
  1331. X        return;
  1332. X    if (tryfile(f, p.path, gfmagdir(p.dirs, f.mag), f.basename, ".gf"))
  1333. X        return;
  1334. X    if (tryfile(f, p.path, gfmagdir(p.dirs, f.mag), f.basename, ""))
  1335. X        return;
  1336. X    if (tryfile(f, p.path, pkmagdir(p.dirs, f.mag), f.basename, ""))
  1337. X        return;
  1338. X    }
  1339. X    quit("Cannot find font file \"%s\" (at or near magnification %ld.%03ld) anywhere",
  1340. X        f.basename, f.mag / 1000, f.mag % 1000);
  1341. }
  1342. X
  1343. X
  1344. // dump the current "fontbits" on screen in a human-readable
  1345. // format - this is really for debugging only
  1346. // 
  1347. void dumpbits(int ch)
  1348. {
  1349. X    register long i, j;
  1350. X    font & f = *currfont;
  1351. X    fontchar & g = f.chr[ch];
  1352. X
  1353. X    // print a row of 2-digit X coordinate values across the top
  1354. X    fprintf(stderr, "     ");
  1355. X    for (j = 0; j <= g.maxm - g.minm; j++)
  1356. X    fprintf(stderr, "%2ld", j + g.minm);
  1357. X    fprintf(stderr, "\n\n");
  1358. X
  1359. X    // print the Y coordinate on both sides of each row of pixels
  1360. X    for (i = g.maxn - g.minn; i >= 0; i--)
  1361. X    {
  1362. X    fprintf(stderr, "%3ld  ", i + g.minn);
  1363. X    for (j = 0; j <= g.maxm - g.minm; j++)
  1364. X        fprintf(stderr, "%s", fontbits[i]->isin(j) ? "[]" : " .");
  1365. X    fprintf(stderr, "  %3ld\n", i + g.minn);
  1366. X    }
  1367. X
  1368. X    // and finally another row of X-coords across the bottom
  1369. X    fprintf(stderr, "\n     ");
  1370. X    for (j = 0; j <= g.maxm - g.minm; j++)
  1371. X    fprintf(stderr, "%2ld", j + g.minm);
  1372. X    fprintf(stderr, "\n");
  1373. }
  1374. X
  1375. X
  1376. // down load the specified character "ch" to the device - we read this
  1377. // character's GF paint commands to build a bitmap of the character in
  1378. // memory - then we download this image to the printer
  1379. // 
  1380. void downchar(int ch, boolean toomany)
  1381. {
  1382. X    font & f = *currfont;
  1383. X    fontchar & g = f.chr[ch];
  1384. X
  1385. X    // is this font file open?
  1386. X    if (f.fp == NULL)
  1387. X    {
  1388. X    // we need to close another font file if we already have the
  1389. X    // maximum number open
  1390. X    if (numfiles >= MAXFILES)
  1391. X    {
  1392. X        register int i;
  1393. X        int fn = -1;
  1394. X        long u = MAXLONG;
  1395. X
  1396. X        // look for the least-recently used font
  1397. X        for (i = 0; i < fontlist.size(); i++)
  1398. X        if (fontlist[i] != NULL && fontlist[i]->fp != NULL
  1399. X            && fontlist[i]->use < u)
  1400. X        {
  1401. X            fn = i;
  1402. X            u = fontlist[i]->use;
  1403. X        }
  1404. X        if (fn < 0)
  1405. X        quit("Cannot open another font file - all fonts are in use");
  1406. X
  1407. X        // close this font file
  1408. X        fclose(fontlist[fn]->fp);
  1409. X        fontlist[fn]->fp = NULL;
  1410. X        numfiles--;
  1411. X        mesg("@");
  1412. X    }
  1413. X
  1414. X    // open the new font file
  1415. X    f.fp = fopen(f.path, F_READ);
  1416. X    if (f.fp == NULL)
  1417. X        quit("Cannot re-open font file \"%s\"", f.path);
  1418. X    numfiles++;
  1419. X    }
  1420. X
  1421. X    switch (f.type)
  1422. X    {
  1423. X    Case GFID:
  1424. X    getgfchar(f, g, ch);
  1425. X    Case PKID:
  1426. X    getpkchar(f, g, ch);
  1427. X    Default:
  1428. X    quit("?!BUG? Internal font type id changed");
  1429. X    }
  1430. X
  1431. X    // show what this character looks like
  1432. X    if (debuglevel > 12)
  1433. X    dumpbits(ch);
  1434. X
  1435. X    // now download this character to the printer...
  1436. X
  1437. X    long width = g.maxm - g.minm + 1;
  1438. X    long height = g.maxn - g.minn + 1;
  1439. X    if (toomany || g.minm < FHMIN || g.minm > FHMAX || width > FWIDTH
  1440. X        || g.maxn < FVMIN || g.maxn > FVMAX || height > FHEIGHT)
  1441. X    {
  1442. X    // char is too big - send it down as a graphics
  1443. X    // image but do NOT mark it as downloaded
  1444. X    if (!toomany)
  1445. X        g.charbig = TRUE;
  1446. X    dev_bigchar(f, g, ch);
  1447. X    return;
  1448. X    }
  1449. X
  1450. X    // this is the usual method...
  1451. X    g.downloaded = TRUE;
  1452. X    dev_downchar(f, g, ch);
  1453. }
  1454. SHAR_EOF
  1455. chmod 0444 readfont.C ||
  1456. echo 'restore of readfont.C failed'
  1457. Wc_c="`wc -c < 'readfont.C'`"
  1458. test 5861 -eq "$Wc_c" ||
  1459.     echo 'readfont.C: original size 5861, current size' "$Wc_c"
  1460. fi
  1461. # ============= gffont.C ==============
  1462. if test -f 'gffont.C' -a X"$1" != X"-c"; then
  1463.     echo 'x - skipping gffont.C (File already exists)'
  1464. else
  1465. echo 'x - extracting gffont.C (Text)'
  1466. sed 's/^X//' << 'SHAR_EOF' > 'gffont.C' &&
  1467. // Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
  1468. static const char rcsid[] = "$Header: gffont.C,v 1.20 91/02/22 15:58:04 hmgr Exp $";
  1469. X
  1470. // read font data from the METAFONT GF (generic font) files
  1471. //
  1472. // by Parag Patel
  1473. X
  1474. #include "defs.h"
  1475. X
  1476. X
  1477. // these are for "drawing" an image of a character in a font
  1478. const int WHITE = FALSE;
  1479. const int BLACK = TRUE;
  1480. X
  1481. X
  1482. // return a string containing the magnification sub-directory for the
  1483. // requested magnification
  1484. // 
  1485. char *gfmagdir(Dirlist &dirlist, long mag)
  1486. {
  1487. X    // look for the closest magnification value to the one desired
  1488. X    int ent = -1;
  1489. X    long diff = MAXLONG;
  1490. X
  1491. X    for (int i = 0; i < dirlist.size(); i++)
  1492. X    {
  1493. X    long d = mag - dirlist[i].val;
  1494. X    long newdiff = d < 0 ? -d : d;    // absolute value
  1495. X    if (newdiff >= diff)
  1496. X        continue;
  1497. X    diff = newdiff;
  1498. X    ent = i;
  1499. X    }
  1500. X
  1501. X    // we should be within 1/32 (.03%) of the desired mag value
  1502. X    if (ent < 0 || diff > (mag >> 5))
  1503. X    return "";
  1504. X
  1505. X    // return the new value as a string
  1506. X    return dirlist[ent].name;
  1507. }
  1508. X
  1509. X
  1510. // setup a GF font file in memory
  1511. //
  1512. void setupgffont(font &f, FILE *fp)
  1513. {
  1514. X    // skip the comment
  1515. X    int len = (int)getuval(1, fp);
  1516. X    while (len-- > 0)
  1517. X    (void)getuval(1, fp);
  1518. X
  1519. X    // now we jump to the end to find the postamble
  1520. X    if (fseek(fp, 0, SEEK_END) != 0)
  1521. X    quit("Cannot seek to end of GF file %s", f.path);
  1522. X
  1523. X    register int op = GFILLER;
  1524. X    long floc = ftell(fp);
  1525. X
  1526. X    // skip the filler bytes at the end of the file
  1527. X    while (op == GFILLER && floc > 0)
  1528. X    {
  1529. X    (void)fseek(fp, --floc, SEEK_SET);
  1530. X    op = (int)getuval(1, fp);
  1531. X    }
  1532. X    if (op != GFID)
  1533. X    quit("Incorrect GF version for %s", f.path);
  1534. X
  1535. X    // now we get the file-pointer to the start of the postamble
  1536. X    (void)fseek(fp, floc -= 4, SEEK_SET);
  1537. X    long postloc = getuval(4, fp);
  1538. X
  1539. X    // verify that we have a POST byte
  1540. X    (void)fseek(fp, postloc, SEEK_SET);
  1541. X    if (getuval(1, fp) != FPOST)
  1542. X    quit("Expected FPOST");
  1543. X
  1544. X    long fsize = getuval(4, fp);// pointer to last EOC in file
  1545. X    debug(3, "GF last EOC=%ld", fsize);
  1546. X
  1547. X    // get and verify that the design size is ok - the GF file stores
  1548. X    // this value as a "fix_word" value while the DVI file keeps it as
  1549. X    // a "scaled-point" value - also note that the "basename" pointer
  1550. X    // is NULL only for the "dumpfont" main program
  1551. X
  1552. X    long dsize = getsval(4, fp);
  1553. X    debug(4, "GF designsize=%ld", dsize);
  1554. X    if (f.basename != NULL && dsize >> 4 != f.designsize)
  1555. X    if (dochecksum && dsize != 0 && f.designsize != 0)
  1556. X        quit("Designsize in DVI and GF file %s does not match", f.path);
  1557. X    else
  1558. X        warn("Designsize in DVI and GF file %s does not match", f.path);
  1559. X
  1560. X    // check the checksum (!)
  1561. X    long check = getuval(4, fp);
  1562. X    debug(5, "GF checksum=%ld", check);
  1563. X    if (f.basename != NULL && check != f.checksum)
  1564. X    if (dochecksum && check != 0 && f.checksum != 0)
  1565. X        quit("Checksums in DVI and GF file %s do not match", f.path);
  1566. X    else
  1567. X        warn("Checksums in DVI and GF file %s do not match", f.path);
  1568. X
  1569. X    // get the horizontal and vertical pixels per point values
  1570. X    f.hppp = getuval(4, fp);
  1571. X    f.vppp = getuval(4, fp);
  1572. X
  1573. X    // get the size ranges of the characters in this font
  1574. X    f.minm = getsval(4, fp);
  1575. X    f.maxm = getsval(4, fp);
  1576. X    f.minn = getsval(4, fp);
  1577. X    f.maxn = getsval(4, fp);
  1578. X
  1579. X    debug(3,"mag=%ld  hppp=%ld vppp=%ld  minm=%ld maxm=%ld  minn=%ld, maxn=%ld",
  1580. X        f.mag, f.hppp, f.vppp, f.minm, f.maxm, f.minn, f.maxn);
  1581. X
  1582. X    // now initialize the info for each character in this font - note
  1583. X    // that there may only be CHARLOC or NOOPs in this part of the file
  1584. X    while ((op = (int)getuval(1, fp)) != FPOSTPOST)
  1585. X    {
  1586. X    if (op == FNOOP)
  1587. X        continue;
  1588. X
  1589. X    // assume that the next byte is a character "residue" (id % 256)
  1590. X    int c = (int)getuval(1, fp);
  1591. X    if (c >= MAXCHARS)
  1592. X        quit("Char %d too big in GF file %s", c, f.path);
  1593. X    fontchar & g = f.chr[c];
  1594. X
  1595. X    // get the values for delta-x, delta-y, width, and file-pointer
  1596. X    // for this character
  1597. X    switch (op)
  1598. X    {
  1599. X    Case CHARLOC:
  1600. X        g.dx = getuval(4, fp);
  1601. X        g.dy = getuval(4, fp);
  1602. X        g.width = Getsval(4, fp);
  1603. X        g.floc = getsval(4, fp);
  1604. X
  1605. X    Case CHARLOC0:
  1606. X        g.dx = getuval(1, fp) << 16;
  1607. X        g.dy = 0;
  1608. X        g.width = Getsval(4, fp);
  1609. X        g.floc = getsval(4, fp);
  1610. X
  1611. X    Default:
  1612. X        quit("Illegal opcode %d in GF postamble", op);
  1613. X    }
  1614. X
  1615. X    g.width = g.width / double(16) * double(f.designsize) /
  1616. X    double(65536L) * double(f.mag) / 1000.0;
  1617. X    }
  1618. }
  1619. X
  1620. X
  1621. // load the specified character "ch" into the bitmap - we read this
  1622. // character's GF paint commands to paint this font
  1623. // 
  1624. void getgfchar(font &f, fontchar &g, int ch)
  1625. {
  1626. X    // go to the file where this character is defined
  1627. X    if (fseek(f.fp, g.floc, SEEK_SET) < 0)
  1628. X    quit("Cannot fseek to start of font in %s", f.path);
  1629. X
  1630. X    register int op = (int)getuval(1, f.fp);
  1631. X
  1632. X    // we had better get some flavor of BOC here...
  1633. X    switch (op)
  1634. X    {
  1635. X    Case BOC:
  1636. X    // verify the character (Just In Case)
  1637. X    if (ch != getsval(4, f.fp))
  1638. X        quit("Character definition for %d does not match", ch);
  1639. X
  1640. X    (void)getuval(4, f.fp);    // pointer to next character % 256
  1641. X
  1642. X    // get the size (in pixels) of this character
  1643. X    g.minm = getsval(4, f.fp);
  1644. X    g.maxm = getsval(4, f.fp);
  1645. X    g.minn = getsval(4, f.fp);
  1646. X    g.maxn = getsval(4, f.fp);
  1647. X
  1648. X    Case BOC1:
  1649. X    if (ch != getuval(1, f.fp))
  1650. X        quit("Character definition for %d does not match", ch);
  1651. X
  1652. X    // decode the size (in pixels) of this character
  1653. X    g.minm = getuval(1, f.fp);
  1654. X    g.maxm = getuval(1, f.fp);
  1655. X    g.minm = g.maxm - g.minm;
  1656. X
  1657. X    g.minn = getuval(1, f.fp);
  1658. X    g.maxn = getuval(1, f.fp);
  1659. X    g.minn = g.maxn - g.minn;
  1660. X
  1661. X    Default:
  1662. X    quit("Expected BOC* (not %d) in font file %s for char %d",
  1663. X        op, f.path, ch);
  1664. X    }
  1665. X
  1666. X    {
  1667. X    int len;
  1668. X    const char *x = dev_char2dev(ch, len);
  1669. X    debug(5, "char=%d(%s)  minm=%ld maxm=%ld  minn=%ld maxn=%ld",
  1670. X        ch, x, g.minm, g.maxm, g.minn, g.maxn);
  1671. X    debug(5, "    dx=%ld dy=%ld  dx/=%ld dy/=%ld  width=%f", g.dx, g.dy,
  1672. X        g.dx >> 16, g.dy >> 16, g.width);
  1673. X    }
  1674. X
  1675. X    // initialize the character painting variables
  1676. X    register long m = 0;
  1677. X    register long n = g.maxn - g.minn;
  1678. X    int p = WHITE;
  1679. X
  1680. X    long width = g.maxm - g.minm + 1;
  1681. X    long height = g.maxn - g.minn + 1;
  1682. X
  1683. X    // clear the global fontbits for the bitmap
  1684. X    register long d;
  1685. X    for (d = f.maxn - f.minn; d >= 0; d--)
  1686. X    fontbits[d]->clear();
  1687. X
  1688. X    // paint the fontbits to build the character
  1689. X    while ((op = (int)getuval(1, f.fp)) != EOC)
  1690. X    {
  1691. X    if (op > PAINT0 && op <= PAINT63)
  1692. X    {
  1693. X        // paint with the current color, advance X
  1694. X        if (p == BLACK)
  1695. X        while (op-- > 0)
  1696. X            *fontbits[n] += m++;
  1697. X        else
  1698. X        m += op;
  1699. X        p = !p;
  1700. X        continue;
  1701. X    }
  1702. X    if (op >= NEWROW0 && op <= NEWROW164)
  1703. X    {
  1704. X        // advance Y, paint to black
  1705. X        n--;
  1706. X        m = op - NEWROW0;
  1707. X        p = BLACK;
  1708. X        continue;
  1709. X    }
  1710. X
  1711. X    switch (op)
  1712. X    {
  1713. X        // paint with current color, advange X
  1714. X    Case PAINT0:
  1715. X        p = !p;
  1716. X    Case PAINT1:
  1717. X        d = getuval(1, f.fp);
  1718. X        if (p == BLACK)
  1719. X        while (d-- > 0)
  1720. X            *fontbits[n] += m++;
  1721. X        else
  1722. X        m += d;
  1723. X        p = !p;
  1724. X    Case PAINT2:
  1725. X        d = getuval(2, f.fp);
  1726. X        if (p == BLACK)
  1727. X        while (d-- > 0)
  1728. X            *fontbits[n] += m++;
  1729. X        else
  1730. X        m += d;
  1731. X        p = !p;
  1732. X    Case PAINT3:
  1733. X        d = getuval(3, f.fp);
  1734. X        if (p == BLACK)
  1735. X        while (d-- > 0)
  1736. X            *fontbits[n] += m++;
  1737. X        else
  1738. X        m += d;
  1739. X        p = !p;
  1740. X
  1741. X        // advance Y, paint to white
  1742. X    Case SKIP0:
  1743. X        n--;
  1744. X        m = 0;
  1745. X        p = WHITE;
  1746. X    Case SKIP1:
  1747. X        n -= getuval(1, f.fp) + 1;
  1748. X        m = 0;
  1749. X        p = WHITE;
  1750. X    Case SKIP2:
  1751. X        n -= getuval(2, f.fp) + 1;
  1752. X        m = 0;
  1753. X        p = WHITE;
  1754. X    Case SKIP3:
  1755. X        n -= getuval(3, f.fp) + 1;
  1756. X        m = 0;
  1757. X        p = WHITE;
  1758. X
  1759. X        // special opcodes - just ignore for now
  1760. X    Case FXXX1:
  1761. X        skipbytes(getuval(1, f.fp), f.fp);
  1762. X    Case FXXX2:
  1763. X        skipbytes(getuval(2, f.fp), f.fp);
  1764. X    Case FXXX3:
  1765. X        skipbytes(getuval(3, f.fp), f.fp);
  1766. X    Case FXXX4:
  1767. X        skipbytes(getuval(4, f.fp), f.fp);
  1768. X
  1769. X        // special numeric opcode - also ignored
  1770. X    Case YYY:
  1771. X        (void)getuval(4, f.fp);
  1772. X
  1773. X    Case FNOOP:
  1774. X
  1775. X    Default:
  1776. X        quit("Illegal GF opcode %ld in file %f", d, f.path);
  1777. X    }
  1778. X    }
  1779. }
  1780. SHAR_EOF
  1781. chmod 0444 gffont.C ||
  1782. echo 'restore of gffont.C failed'
  1783. Wc_c="`wc -c < 'gffont.C'`"
  1784. test 7918 -eq "$Wc_c" ||
  1785.     echo 'gffont.C: original size 7918, current size' "$Wc_c"
  1786. fi
  1787. true || echo 'restore of pkfont.C failed'
  1788. echo End of part 2, continue with part 3
  1789. exit 0
  1790.  
  1791. exit 0 # Just in case...
  1792. -- 
  1793. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1794. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1795. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1796. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1797.