home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume37 / lout / part03 < prev    next >
Text File  |  1993-06-01  |  83KB  |  2,041 lines

  1. Newsgroups: comp.sources.misc
  2. From: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  3. Subject: v37i101:  lout - Lout document formatting system, v2, Part03/30
  4. Message-ID: <1993May31.035132.20649@sparky.imd.sterling.com>
  5. X-Md4-Signature: 57e41a94eef8653ac41a71e135813f34
  6. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Mon, 31 May 1993 03:51:32 GMT
  9. Approved: kent@sparky.imd.sterling.com
  10.  
  11. Submitted-by: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  12. Posting-number: Volume 37, Issue 101
  13. Archive-name: lout/part03
  14. Environment: UNIX
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # Contents:  lout/z20.c lout/z24.c
  21. # Wrapped by kent@sparky on Sun May 30 19:43:53 1993
  22. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 3 (of 30)."'
  25. if test -f 'lout/z20.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'lout/z20.c'\"
  27. else
  28.   echo shar: Extracting \"'lout/z20.c'\" \(22873 characters\)
  29.   sed "s/^X//" >'lout/z20.c' <<'END_OF_FILE'
  30. X/*@z20.c:Galley Flushing:FlushGalley()@***************************************/
  31. X/*                                                                           */
  32. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  33. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  34. X/*                                                                           */
  35. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  36. X/*  Basser Department of Computer Science                                    */
  37. X/*  The University of Sydney 2006                                            */
  38. X/*  AUSTRALIA                                                                */
  39. X/*                                                                           */
  40. X/*  This program is free software; you can redistribute it and/or modify     */
  41. X/*  it under the terms of the GNU General Public License as published by     */
  42. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  43. X/*  any later version.                                                       */
  44. X/*                                                                           */
  45. X/*  This program is distributed in the hope that it will be useful,          */
  46. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  47. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  48. X/*  GNU General Public License for more details.                             */
  49. X/*                                                                           */
  50. X/*  You should have received a copy of the GNU General Public License        */
  51. X/*  along with this program; if not, write to the Free Software              */
  52. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  53. X/*                                                                           */
  54. X/*  FILE:         z20.c                                                      */
  55. X/*  MODULE:       Galley Flushing                                            */
  56. X/*  EXTERNS:      FlushGalley()                                              */
  57. X/*                                                                           */
  58. X/*****************************************************************************/
  59. X#include "externs"
  60. X
  61. X
  62. X/*****************************************************************************/
  63. X/*                                                                           */
  64. X/*  ParentFlush(dest_index, kill)                                            */
  65. X/*                                                                           */
  66. X/*  Flush the galley which is the parent of dest_index, if likely to flush.  */
  67. X/*  If kill is TRUE, delete dest_index.                                      */
  68. X/*                                                                           */
  69. X/*****************************************************************************/
  70. X
  71. X#define ParentFlush(dest_index, kill)                    \
  72. Xif( prnt_flush )                            \
  73. X{ debug0(DGF,D, "  ParentFlush calling FlushGalley (prnt)");        \
  74. X  Parent(prnt, Up(dest_index));                        \
  75. X  if( kill )  DeleteNode(dest_index);                    \
  76. X  debug0(DGF, D, "  calling FlushGalley from ParentFlush");        \
  77. X  FlushGalley(prnt);                            \
  78. X  prnt_flush = FALSE;                            \
  79. X}                                    \
  80. Xelse if( kill )  DeleteNode(dest_index)
  81. X
  82. X
  83. X/*****************************************************************************/
  84. X/*                                                                           */
  85. X/*  FlushGalley(hd)                                                          */
  86. X/*                                                                           */
  87. X/*  Flush galley hd as far as possible.  It could be the root galley.        */
  88. X/*                                                                           */
  89. X/*****************************************************************************/
  90. X
  91. XFlushGalley(hd)
  92. XOBJECT hd;
  93. X{ OBJECT dest;            /* the target galley hd empties into         */
  94. X  OBJECT dest_index;        /* the index of dest                         */
  95. X  OBJECT inners;        /* list of galleys and PRECEDES to flush     */
  96. X  OBJECT link, y;        /* for scanning through the components of hd */
  97. X
  98. X  CONSTRAINT dest_constraint;    /* the vertical size constraint on dest      */
  99. X  int f;            /* candidate replacement value for dest_fwd  */
  100. X
  101. X  OBJECT dest_encl;        /* the VCAT enclosing dest, if any           */
  102. X  int    dest_side;        /* if dest_encl != nil, the side dest is on  */
  103. X  BOOLEAN need_adjust;        /* TRUE as soon as dest_encl needs adjusting */
  104. X  LENGTH dest_back, dest_fwd;    /* the current size of dest_encl or dest     */
  105. X  LENGTH frame_size;        /* the total constraint of dest_encl         */
  106. X  OBJECT prec_gap;        /* the gap preceding dest, if any, else nil  */
  107. X  OBJECT prec_def;        /* the component preceding dest, if any      */
  108. X  OBJECT succ_gap;        /* the gap following dest, if any, else nil  */
  109. X  OBJECT succ_def;        /* the component following dest, if any      */
  110. X  OBJECT stop_link;        /* most recently seen gap link of hd         */
  111. X  BOOLEAN prnt_flush;        /* TRUE when hd's parent needs a flush       */
  112. X  OBJECT zlink, z, tmp, prnt;
  113. X
  114. X  debug1(DGF, D, "[ FlushGalley %s (hd)", SymName(actual(hd)));
  115. X  prnt_flush = FALSE;
  116. X
  117. X  RESUME:
  118. X  assert( type(hd) == HEAD, "FlushGalley: type(hd) != HEAD!" );
  119. X  debug1(DGF, D, "  resuming FlushGalley %s, hd =", SymName(actual(hd)));
  120. X  ifdebug(DGF, DD, EchoObject(stderr, hd));
  121. X  assert( Up(hd) != hd, "FlushGalley: resume found no parent to hd!" );
  122. X
  123. X
  124. X  /*@@************************************************************************/
  125. X  /*                                                                         */
  126. X  /*  The first step is to examine the parent of galley hd to determine the  */
  127. X  /*  status of the galley.  If this is not suitable for flushing, we do     */
  128. X  /*  what we can to change the status.  If still no good, return; so if     */
  129. X  /*  this code does not return, then the galley is ready to flush into a    */
  130. X  /*  destination in the normal way, and the following variables are set:    */
  131. X  /*                                                                         */
  132. X  /*      dest_index     the galley's parent and index of its destination    */
  133. X  /*      dest           the galley's destination, a @Galley object          */
  134. X  /*                                                                         */
  135. X  /***************************************************************************/
  136. X
  137. X  Parent(dest_index, Up(hd));
  138. X  switch( type(dest_index) )
  139. X  {
  140. X
  141. X    case DEAD:
  142. X    
  143. X      /* the galley has been killed off while this process was sleeping */
  144. X      debug1(DGF, D, "] FlushGalley %s returning (DEAD)", SymName(actual(hd)));
  145. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  146. X      return;
  147. X
  148. X
  149. X    case UNATTACHED:
  150. X    
  151. X      /* the galley is currently not attached to a destination */
  152. X      AttachGalley(hd, &inners);
  153. X      Parent(dest_index, Up(hd));
  154. X      if( type(dest_index)!=RECEIVING || actual(actual(dest_index))==InputSym )
  155. X      {    if( type(dest_index) != DEAD )
  156. X    { ParentFlush(dest_index, FALSE);
  157. X      if( inners != nil ) FlushInners(inners, nil);
  158. X    }
  159. X    debug1(DGF,D,"] FlushGalley %s retn, no attach", SymName(actual(hd)));
  160. X    debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  161. X    return;
  162. X      }
  163. X
  164. X      /* if hd is a forcing galley, close all predecessors */
  165. X      if( actual(hd) != nil && force_target(actual(hd)) )
  166. X      {    Parent(prnt, Up(dest_index));
  167. X    debug0(DGA, DD, "  force: prnt =");
  168. X    ifdebug(DGA, DD, EchoObject(stderr, prnt));
  169. X    debug1(DGA, D,"  calling FreeGalley from FlushGalley(%s)",
  170. X      SymName(actual(hd)));
  171. X    FreeGalley(prnt, Up(dest_index), &inners, Up(dest_index), whereto(hd));
  172. X    prnt_flush = TRUE;
  173. X    debug0(DGA, DD, "  force: after FreeGalley, prnt =");
  174. X    ifdebug(DGA, DD, EchoObject(stderr, prnt));
  175. X      }
  176. X      else prnt_flush = prnt_flush || blocked(dest_index);
  177. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  178. X
  179. X      if( inners != nil ) FlushInners(inners, nil);
  180. X      goto RESUME;
  181. X      break;
  182. X
  183. X
  184. X    case RECEIVING:
  185. X    
  186. X      if( actual(actual(dest_index)) == InputSym )
  187. X      { ParentFlush(dest_index, FALSE);
  188. X    debug1(DGF, D, "] FlushGalley %s retn, input", SymName(actual(hd)));
  189. X    debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  190. X    return;
  191. X      }
  192. X      break;
  193. X
  194. X
  195. X    default:
  196. X    
  197. X      Error(INTERN, &fpos(hd), "FlushGalley: %s ind!", Image(type(dest_index)));
  198. X      break;
  199. X  }
  200. X  dest = actual(dest_index);
  201. X  debug1(DGF, DD, "  dest_index: %s", EchoObject(null, dest_index));
  202. X
  203. X
  204. X  /*@@************************************************************************/
  205. X  /*                                                                         */
  206. X  /*  The second step is to examine the components of the galley one by one  */
  207. X  /*  to determine if they can be promoted.  Each component has the format   */
  208. X  /*                                                                         */
  209. X  /*    { <index> } <object>                                                 */
  210. X  /*                                                                         */
  211. X  /*  and is always followed by a gap object (except the last component).    */
  212. X  /*  An index indicates that the following object has some interesting      */
  213. X  /*  feature, and it points to that feature inside the object.  There are   */
  214. X  /*  two possible actions for each component, in addition to accepting it:  */
  215. X  /*                                                                         */
  216. X  /*    REJECT:   The component does not fit, so detach the galley           */
  217. X  /*    SUSPEND:  The component is incomplete; go to sleep and wait          */
  218. X  /*                                                                         */
  219. X  /***************************************************************************/
  220. X
  221. X  stop_link = dest_encl = inners = nil;
  222. X  need_adjust = FALSE;
  223. X
  224. X  /***************************************************************************/
  225. X  /*                                                                         */
  226. X  /*  Loop invariant                                                         */
  227. X  /*                                                                         */
  228. X  /*  The children of hd up to but not including Child(link) have been       */
  229. X  /*  examined and pronounced to be promotable.                              */
  230. X  /*                                                                         */
  231. X  /*  stop_link is the link of the most recently encountered gap object of   */
  232. X  /*  hd, or nil if no gap object has been encountered yet.                  */
  233. X  /*                                                                         */
  234. X  /*  if dest_encl is non-nil, then the destination is not external,         */
  235. X  /*  dest_encl is its parent, and the following variables are defined:      */
  236. X  /*                                                                         */
  237. X  /*    prec_gap         gap object preceding dest (which must exist)        */
  238. X  /*    prec_def         first definite object preceding dest (must exist)   */
  239. X  /*    dest_back        back(dest_encl) including effect of accepted compts */
  240. X  /*    dest_fwd         fwd(dest_encl) including effect of accepted compts  */
  241. X  /*    dest_side        BACK or FWD indicating dest's side of the mark      */
  242. X  /*    dest_constraint  the size constraint on dest                         */
  243. X  /*    frame_size       size of frame enclosing dest_encl                   */
  244. X  /*                                                                         */
  245. X  /*  if dest_encl is nil, these variables are not defined.                  */
  246. X  /*                                                                         */
  247. X  /*  need_adjust is true if at least one definite component has been        */
  248. X  /*  accepted for promotion and the destination is internal; hence,         */
  249. X  /*  dest_encl is defined and its size needs to be adjusted.                */
  250. X  /*                                                                         */
  251. X  /*  inners is the set of all PRECEDES and UNATTACHED indexes found.        */
  252. X  /*                                                                         */
  253. X  /***************************************************************************/
  254. X
  255. X  for( link = Down(hd);  link != hd;  link = NextDown(link) )
  256. X  {
  257. X    Child(y, link);
  258. X    if( type(y) == SPLIT )  Child(y, DownDim(y, ROW));
  259. X    debug1(DGF, DD, "  try to flush %s", EchoObject(null, y));
  260. X    switch( type(y) )
  261. X    {
  262. X
  263. X      case GAP_OBJ:
  264. X
  265. X    prec_gap = y;
  266. X    stop_link = link;
  267. X    if( !join(gap(y)) )  seen_nojoin(hd) = TRUE;
  268. X    break;
  269. X
  270. X
  271. X      case EXPAND_IND:
  272. X      case GALL_PREC:
  273. X      case GALL_FOLL:
  274. X      case GALL_TARG:
  275. X      case CROSS_PREC:
  276. X      case CROSS_FOLL:
  277. X      case CROSS_TARG:
  278. X
  279. X    break;
  280. X
  281. X
  282. X      case PRECEDES:
  283. X      case UNATTACHED:
  284. X      
  285. X    if( inners == nil )  inners = New(ACAT);
  286. X    Link(inners, y);
  287. X    break;
  288. X
  289. X
  290. X      case RECEIVING:
  291. X      case RECEPTIVE:
  292. X      
  293. X    goto SUSPEND;
  294. X
  295. X
  296. X      case FOLLOWS:
  297. X      
  298. X    Child(tmp, Down(y));
  299. X    if( Up(tmp) == LastUp(tmp) )
  300. X    { link = PrevDown(link);
  301. X      DisposeChild(NextDown(link));
  302. X      break;
  303. X    }
  304. X    Parent(tmp, Up(tmp));
  305. X    assert(type(tmp) == PRECEDES, "Flush: PRECEDES!");
  306. X    switch( CheckConstraint(tmp, dest_index) )
  307. X    {
  308. X      case CLEAR:    DeleteNode(tmp);
  309. X            link = PrevDown(link);
  310. X            DisposeChild(NextDown(link));
  311. X            break;
  312. X
  313. X      case PROMOTE:    break;
  314. X
  315. X      case BLOCK:    goto SUSPEND;
  316. X
  317. X      case CLOSE:    goto REJECT;
  318. X    }
  319. X    break;
  320. X
  321. X
  322. X      case WORD:
  323. X      case ONE_COL:
  324. X      case ONE_ROW:
  325. X      case WIDE:
  326. X      case HIGH:
  327. X      case HSCALE:
  328. X      case VSCALE:
  329. X      case HCONTRACT:
  330. X      case VCONTRACT:
  331. X      case HEXPAND:
  332. X      case VEXPAND:
  333. X      case PADJUST:
  334. X      case HADJUST:
  335. X      case VADJUST:
  336. X      case ROTATE:
  337. X      case SCALE:
  338. X      case INCGRAPHIC:
  339. X      case SINCGRAPHIC:
  340. X      case GRAPHIC:
  341. X      case ACAT:
  342. X      case HCAT:
  343. X      case ROW_THR:
  344. X      case CLOSURE:
  345. X      case NULL_CLOS:
  346. X      case CROSS:
  347. X
  348. X    /* make sure y is not joined to a target below */
  349. X    for( zlink = NextDown(link); zlink != hd; zlink = NextDown(zlink) )
  350. X    { Child(z, zlink);
  351. X      switch( type(z) )
  352. X      {
  353. X        case RECEPTIVE:
  354. X        case RECEIVING:    y = z;
  355. X                goto SUSPEND;
  356. X                break;
  357. X
  358. X        case GAP_OBJ:    if( !join(gap(z)) )  zlink = PrevDown(hd);
  359. X                break;
  360. X
  361. X        default:        break;
  362. X      }
  363. X    }
  364. X
  365. X    /* check size constraint */
  366. X    if( !external(dest) )
  367. X    {
  368. X      /* initialise dest_encl etc if not done yet */
  369. X      if( dest_encl == nil )
  370. X      { assert( UpDim(dest,COL) == UpDim(dest,ROW), "FlushG: UpDims!" );
  371. X        Parent(dest_encl, NextDown(Up(dest)));
  372. X        assert( type(dest_encl) == VCAT, "FlushGalley: dest != VCAT!" );
  373. X        SetNeighbours(Up(dest), FALSE, &prec_gap, &prec_def,
  374. X          &succ_gap, &succ_def, &dest_side);
  375. X        assert(prec_gap != nil || is_indefinite(type(y)),
  376. X          "FlushGalley: prec_gap == nil && !is_indefinite(type(y))!" );
  377. X        assert(succ_gap == nil, "FlushGalley: succ_gap != nil!" );
  378. X        assert(dest_side == FWD || is_indefinite(type(y)),
  379. X          "FlushGalley: dest_side != FWD || !is_indefinite(type(y))!");
  380. X        dest_back = back(dest_encl, ROW);
  381. X        dest_fwd  = fwd(dest_encl, ROW);
  382. X        Constrained(dest_encl, &dest_constraint, ROW);
  383. X        frame_size = constrained(dest_constraint) ? bfc(dest_constraint) :0;
  384. X      }
  385. X
  386. X      if( !is_indefinite(type(y)) )
  387. X      { /* calculate effect of adding y to dest */
  388. X        f = dest_fwd  + fwd(y, ROW) - fwd(prec_def, ROW) +
  389. X          ActualGap(fwd(prec_def, ROW), back(y, ROW),
  390. X            fwd(y, ROW), &gap(prec_gap), frame_size,
  391. X            dest_back + dest_fwd - fwd(prec_def, ROW));
  392. X        debug3(DGF, DD, "  b,f: %s,%s;   dest_encl: %s",
  393. X            EchoLength(dest_back), EchoLength(f),
  394. X            EchoConstraint(&dest_constraint));
  395. X
  396. X        /* check new size against constraint */
  397. X        if( !FitsConstraint(dest_back,f,dest_constraint) )
  398. X          goto REJECT;
  399. X        if( units(gap(prec_gap))==FRAME_UNIT && width(gap(prec_gap)) > FR )
  400. X          goto REJECT;
  401. X
  402. X        /* accept component */
  403. X        dest_fwd = f;  prec_def = y;
  404. X        need_adjust = TRUE;
  405. X      }
  406. X
  407. X    } /* end if( !external(dest) ) */
  408. X
  409. X    /* accept this component into dest */
  410. X    debug1(DGF, D, "  accept %s", EchoObject(null, y));
  411. X    prnt_flush = prnt_flush || blocked(dest_index);
  412. X    debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  413. X    if( inners != nil )
  414. X    { Promote(hd, NextDown(link), dest_index);
  415. X      if( need_adjust )
  416. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (ACCEPT)");
  417. X        AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  418. X      }
  419. X      FlushInners(inners, hd);
  420. X      goto RESUME;
  421. X    }
  422. X    break;
  423. X
  424. X
  425. X      default:
  426. X      
  427. X    Error(INTERN, &fpos(y), "FlushGalley: %s", Image(type(y)));
  428. X    break;
  429. X
  430. X    } /* end switch */
  431. X
  432. X  } /* end for */
  433. X
  434. X
  435. X  /* EMPTY: */
  436. X
  437. X    /* galley is now completely accepted; clean up and exit */
  438. X    debug0(DGF, DD, "  galley empty now");
  439. X    if( inners != nil )  DisposeObject(inners);
  440. X    if( Down(hd) != hd )
  441. X    { Promote(hd, hd, dest_index);
  442. X      if( need_adjust )
  443. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (EMPTY)");
  444. X    AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  445. X      }
  446. X    }
  447. X    DetachGalley(hd);
  448. X    debug0(DGF, D, "  calling KillGalley from FlushGalley");
  449. X    KillGalley(hd);
  450. X    ParentFlush(dest_index, TRUE);
  451. X    debug1(DGF,D,"] FlushGalley %s returning (emptied).", SymName(actual(hd)));
  452. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  453. X    return;
  454. X
  455. X
  456. X  REJECT:
  457. X  
  458. X    /* reject this component and move to a new dest */
  459. X    debug1(DGF, D, "  reject %s", EchoObject(null, y));
  460. X    assert(actual(dest) != PrintSym, "FlushGalley: reject print!");
  461. X    if( inners != nil )  DisposeObject(inners);
  462. X    if( stop_link != nil )
  463. X    { Promote(hd, stop_link, dest_index);
  464. X      if( need_adjust )
  465. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (REJECT)");
  466. X    AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  467. X      }
  468. X    }
  469. X    DetachGalley(hd);
  470. X    assert( type(dest_index) == RECEIVING, "FlushGalley/REJECT: dest_index!" );
  471. X    prnt_flush = prnt_flush || blocked(dest_index); /* **** bug fix **** */
  472. X    DeleteNode(dest_index);
  473. X    goto RESUME;
  474. X
  475. X
  476. X  SUSPEND:
  477. X  
  478. X    /* suspend this component */
  479. X    debug1(DGF, D, "  suspend %s", EchoObject(null, y));
  480. X    if( inners != nil )  DisposeObject(inners);
  481. X    if( stop_link != nil )
  482. X    { Promote(hd, stop_link, dest_index);
  483. X      if( need_adjust )
  484. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (SUSPEND)");
  485. X    AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  486. X      }
  487. X    }
  488. X
  489. X    /* check whether external galleys can remove the blockage */
  490. X    if( type(y) == RECEPTIVE && ready_galls(hd) != nil && AllowCrossDb )
  491. X    { OBJECT eg, val, index2, hd2, tag, seq, newsym;
  492. X      BOOLEAN found, gall;  unsigned char newtag[MAX_LINE], newseq[MAX_LINE];
  493. X
  494. X      /* get first ready galley in from cross reference database */
  495. X      Child(eg, Down(ready_galls(hd)));
  496. X      val = ReadFromFile(eg_fnum(eg), eg_fpos(eg), nil);
  497. X      if( val == nil ) Error(FATAL, &fpos(y),
  498. X    "Error in database file %s", FileName(eg_fnum(eg)));
  499. X      assert( type(val) == CLOSURE, "AttachG: db CLOSURE!" );
  500. X      index2 = New(UNATTACHED);
  501. X      hd2 = New(HEAD);
  502. X      FposCopy(fpos(hd2), fpos(val));
  503. X      actual(hd2) = actual(val);
  504. X      backward(hd2) = TargetSymbol(val, &whereto(hd2));
  505. X      backward(hd2) = sized(hd2) = FALSE;
  506. X      ready_galls(hd2) = nil;
  507. X      must_expand(hd2) = TRUE;
  508. X      Link(index2, hd2);
  509. X      Link(hd2, val);
  510. X      Link(Up(y), index2);
  511. X
  512. X      /* set up the next ready galley for reading next time */
  513. X      Child(tag, Down(eg));  Child(seq, LastDown(eg));
  514. X      do /* skip duplicate seq values */
  515. X      {    found = DbRetrieveNext(OldCrossDb, &gall, &newsym,
  516. X         newtag, newseq, &eg_fnum(eg), &eg_fpos(eg), &eg_cont(eg));
  517. X    debug2(DGF, D, "  ext gall  found:   %15s  gall:    %15s",
  518. X            bool(gall), bool(found));
  519. X    debug2(DGF, D, "  ext gall  new sym: %15s  old sym: %15s",
  520. X            SymName(newsym), SymName(eg_symbol(eg)));
  521. X    debug2(DGF, D, "  ext gall  new tag: %15s  old tag: %15s",
  522. X            newtag, string(tag));
  523. X    debug2(DGF, D, "  ext gall  new seq: %15s  old seq: %15s",
  524. X            newseq, string(seq));
  525. X    if( found )  found = gall && newsym == eg_symbol(eg) &&
  526. X            strcmp(newtag, string(tag)) == 0;
  527. X      } while( found && strcmp(newseq, string(seq)) == 0 );
  528. X      if( found )
  529. X      {    DisposeChild(Up(tag));
  530. X    DisposeChild(Up(seq));
  531. X    tag = MakeWord(newtag, no_fpos);
  532. X    seq = MakeWord(newseq, no_fpos);
  533. X    Link(eg, tag);  Link(eg, seq);
  534. X    debug1(DGF,D, "  another ext gall: into %s", SymName(newsym));
  535. X      }
  536. X      else
  537. X      {    DisposeChild(Up(eg));
  538. X    debug1(DGF,D, "  last ext gall into ", SymName(eg_symbol(eg)));
  539. X    if( Down(ready_galls(hd)) == ready_galls(hd) )
  540. X    { Dispose(ready_galls(hd));
  541. X      ready_galls(hd) = nil;
  542. X      debug0(DGF,D, "  all ext galls exhausted");
  543. X    }
  544. X      }
  545. X
  546. X      /* flush the ready galley found above, and resume */
  547. X      debug2(DGF, D, "  ext gall FlushGalley (%s into %s)",
  548. X            SymName(actual(hd2)), SymName(whereto(hd2)));
  549. X      debug0(DGF, D, "  calling FlushGalley from FlushGalley/SUSPEND");
  550. X      FlushGalley(hd2);
  551. X      goto RESUME;
  552. X    }
  553. X    else if( type(y) == RECEPTIVE && trigger_externs(y) && AllowCrossDb )
  554. X    { OBJECT sym, cr, ins, tag, seq, eg, cnt;  BOOLEAN found;
  555. X      unsigned char newseq[MAX_LINE];  FILE_NUM tfnum;  long tfpos, tcont;
  556. X      debug1(DGF, D, "  ext gall target %s", SymName(actual(actual(y))));
  557. X      for( sym = FirstExternTarget(actual(actual(y)), &cnt);
  558. X         sym != nil;  sym = NextExternTarget(actual(actual(y)), &cnt) )
  559. X      {
  560. X    debug1(DGF, D, "  ext gall gall_targ %s", SymName(sym));
  561. X    cr = GallTargEval(sym, &fpos(actual(y)));
  562. X    ins = New(GALL_TARG);
  563. X    actual(ins) = cr;
  564. X    Link(Up(y), ins);
  565. X    Child(tag, LastDown(cr));
  566. X    assert( type(tag) == WORD, "FlushGalley: cr tag WORD!" );
  567. X    found = DbRetrieve(OldCrossDb, TRUE, sym, string(tag),
  568. X        newseq, &tfnum, &tfpos, &tcont);
  569. X    if( found )
  570. X    { if( ready_galls(hd) == nil )  ready_galls(hd) = New(ACAT);
  571. X      eg = New(EXT_GALL);
  572. X      debug1(DGF, D, "  ext gall retrieved: into %s", SymName(sym));
  573. X      eg_fnum(eg) = tfnum;
  574. X      eg_fpos(eg) = tfpos;
  575. X      eg_symbol(eg) = sym;
  576. X      eg_cont(eg) = tcont;
  577. X      tag = MakeWord(string(tag), no_fpos);
  578. X      Link(eg, tag);
  579. X      seq = MakeWord(newseq, no_fpos);
  580. X      Link(eg, seq);
  581. X      Link(ready_galls(hd), eg);
  582. X    }
  583. X      }
  584. X      trigger_externs(y) = FALSE;
  585. X      if( ready_galls(hd) != nil )  goto RESUME;
  586. X    } /* end if external galleys */
  587. X
  588. X    /* if non-blocking, delete the index and resume */
  589. X    if( type(y) == RECEPTIVE && non_blocking(y) )
  590. X    { DeleteNode(y);
  591. X      goto RESUME;
  592. X    }
  593. X    else if( type(y) == RECEIVING && non_blocking(y) )
  594. X    {    
  595. X      if( Down(y) == y )
  596. X      {    DeleteNode(y);
  597. X      }
  598. X      else
  599. X      {    Child(z, Down(y));
  600. X    DetachGalley(z);
  601. X      }
  602. X      goto RESUME;
  603. X    }
  604. X
  605. X    /* if all the above fail to remove the blockage, suspend */
  606. X    blocked(y) = TRUE;
  607. X    ParentFlush(dest_index, FALSE);
  608. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  609. X    debug1(DGF, D, "] FlushGalley %s returning (suspend)", SymName(actual(hd)));
  610. X    return;
  611. X
  612. X} /* end FlushGalley */
  613. END_OF_FILE
  614.   if test 22873 -ne `wc -c <'lout/z20.c'`; then
  615.     echo shar: \"'lout/z20.c'\" unpacked with wrong size!
  616.   fi
  617.   # end of 'lout/z20.c'
  618. fi
  619. if test -f 'lout/z24.c' -a "${1}" != "-c" ; then 
  620.   echo shar: Will not clobber existing file \"'lout/z24.c'\"
  621. else
  622.   echo shar: Extracting \"'lout/z24.c'\" \(56122 characters\)
  623.   sed "s/^X//" >'lout/z24.c' <<'END_OF_FILE'
  624. X/*@z24.c:Back End:FontDefine(), FontChange(), FontAtomSize()@*****************/
  625. X/*                                                                           */
  626. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  627. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  628. X/*                                                                           */
  629. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  630. X/*  Basser Department of Computer Science                                    */
  631. X/*  The University of Sydney 2006                                            */
  632. X/*  AUSTRALIA                                                                */
  633. X/*                                                                           */
  634. X/*  This program is free software; you can redistribute it and/or modify     */
  635. X/*  it under the terms of the GNU General Public License as published by     */
  636. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  637. X/*  any later version.                                                       */
  638. X/*                                                                           */
  639. X/*  This program is distributed in the hope that it will be useful,          */
  640. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  641. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  642. X/*  GNU General Public License for more details.                             */
  643. X/*                                                                           */
  644. X/*  You should have received a copy of the GNU General Public License        */
  645. X/*  along with this program; if not, write to the Free Software              */
  646. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  647. X/*                                                                           */
  648. X/*  FILE:         z24.c                                                      */
  649. X/*  MODULE:       PostScript Back End                                        */
  650. X/*  EXTERNS:      PrintInit(), FontStripQuotes(), FontDefine(),              */
  651. X/*                FontChange(), FontAtomSize(), FontSize(),                  */
  652. X/*                PrintPrologue(), PrintOriginIncrement(), PrintAtom(),      */
  653. X/*                PrintClose()                                               */
  654. X/*                CoordTranslate(), CoordRotate(), CoordScale(),             */
  655. X/*                SaveGraphicState(), RestoreGraphicState(),                 */
  656. X/*                DefineGraphicNames, PrintGraphicObject()                   */
  657. X/*                                                                           */
  658. X/*  This module implements Lout's PostScript back end, by reading Adobe      */
  659. X/*  font metrics files (.AFM files, version 2) and writing PostScript.       */
  660. X/*                                                                           */
  661. X/*****************************************************************************/
  662. X#include "externs"
  663. X#define DEFAULT_XHEIGHT 500
  664. X
  665. X#define printnum(x, fp)                            \
  666. X{ unsigned char buff[20];  register int i, y;                \
  667. X  if( x < 0 )                                \
  668. X  { y = -x;                                \
  669. X    putc('-', fp);                            \
  670. X  }                                    \
  671. X  else y = x;                                \
  672. X  i = 0;                                \
  673. X  do                                    \
  674. X  { buff[i++] = (y % 10) + '0';                        \
  675. X  } while( y = y / 10 );                        \
  676. X  do                                    \
  677. X  { putc(buff[--i], fp);                        \
  678. X  } while( i );                                \
  679. X}
  680. X
  681. X
  682. X/*****************************************************************************/
  683. X/*                                                                           */
  684. X/*  FirstChar(str, ch, xfpos)                                                */
  685. X/*  NextChar(str, ch, xfpos)                                                 */
  686. X/*                                                                           */
  687. X/*  FirstChar sets ch to the true (interpreted) value of the first           */
  688. X/*  character of Lout string str.  NextChar sets ch to the true value of     */
  689. X/*  the next character, repeatedly.  Both set ch to '\0' at end of string.   */
  690. X/*                                                                           */
  691. X/*****************************************************************************/
  692. X
  693. X#define FirstChar(str, ch, xfpos)    p = str;  NextChar(str, ch, xfpos)
  694. X
  695. X#define NextChar(str, ch, xfpos)                    \
  696. X  while( *p == '"' )  p++;                        \
  697. X  if( *p != '\\' )  ch = *p++;                        \
  698. X  else if( *++p >= '0' && *p <= '7' )                    \
  699. X  { int count;                                \
  700. X    count = ch = 0;                            \
  701. X    do                                    \
  702. X    { ch = ch * 8 + *p++ - '0';                        \
  703. X      count++;                                \
  704. X    } while( *p >= '0' && *p <= '7' && count < 3 );            \
  705. X    if( ch == '\0' )  Error(WARN, xfpos, "null character \\0 in word");    \
  706. X  }                                    \
  707. X  else if( *p == '"'  )  ch = '"',  ++p;                \
  708. X  else if( *p == '\\' )  ch = '\\', ++p;                \
  709. X  else                                    \
  710. X  { Error(WARN, xfpos, "unknown ecape sequence \\%c in word", *p);    \
  711. X    ch = *p++;                                \
  712. X  }
  713. X
  714. X
  715. X/*****************************************************************************/
  716. X/*                                                                           */
  717. X/*  CheckLigature(str, ch, lig)                                              */
  718. X/*                                                                           */
  719. X/*  Check whether character ch from string str starts a ligature.  Use lig   */
  720. X/*  as the source of information about what ligatures there are.  If ch      */
  721. X/*  does start a ligature, skip it and change ch to the ligature character.  */
  722. X/*                                                                           */
  723. X/*  CheckLigature also modifies any ligature it finds to the form \?"""      */
  724. X/*  where ? denotes the ligature character (assumed to be different from     */
  725. X/*  the characters which normally may follow a \, i.e. 0123456789"\), and    */
  726. X/*  " is used to fill up space.                                              */
  727. X/*                                                                           */
  728. X/*****************************************************************************/
  729. X
  730. X#define CheckLigature(str, ch, lig)                    \
  731. X  if( lig[ch] )                                \
  732. X  { unsigned char *a, *b;                        \
  733. X    a = &lig[lig[ch] + MAX_CHARS];                    \
  734. X    debug3(DFT, D, "  CheckLigature(%s, %c, %s)", str, ch, a);        \
  735. X    while( *a++ == ch )                            \
  736. X    { b = p;                                \
  737. X      debug2(DFT, D, "  checking a = %s, b = %s", a, b);        \
  738. X      while( *a == *b && *(a+1) != '\0' && *b != '\0' )  a++, b++;    \
  739. X      if( *(a+1) == '\0' )                        \
  740. X      { *(p-1) = '\\';                            \
  741. X    *p = ch = *a;                            \
  742. X    while( ++p < b ) *p = '"';                    \
  743. X        debug1(DFT, D, "  success: now str = %s", str);            \
  744. X    break;                                \
  745. X      }                                    \
  746. X      else                                \
  747. X      { while( *++a );  a++;                        \
  748. X        debug0(DFT, D, "  failure");                    \
  749. X      }                                    \
  750. X    }                                    \
  751. X  }
  752. X
  753. X
  754. X/*****************************************************************************/
  755. X/*                                                                           */
  756. X/*  FontStripQuotes(str, xfpos)                                              */
  757. X/*                                                                           */
  758. X/*  Destructively replace str by its unquoted version.                       */
  759. X/*                                                                           */
  760. X/*****************************************************************************/
  761. X
  762. XFontStripQuotes(str, xfpos)
  763. Xunsigned char *str;  FILE_POS *xfpos;
  764. X{ unsigned char *p, *q;
  765. X  int ch;
  766. X  debug1(DFT, D, "FontStripQuotes( %s )", str);
  767. X  q = str;  FirstChar(str, ch, xfpos);
  768. X  while( ch != '\0' )
  769. X  { *q++ = ch;
  770. X    NextChar(str, ch, xfpos);
  771. X  }
  772. X  *q++ = '\0';
  773. X  debug1(DFT, D, "FontStripQuotes returning, result is %s", str);
  774. X} /* end FontStripQuotes */
  775. X
  776. X
  777. X/*@@**************************************************************************/
  778. X/*                                                                           */
  779. X/*  Definitions for metrics                                                  */
  780. X/*                                                                           */
  781. X/*****************************************************************************/
  782. X
  783. X#define    NO_FONT          0    /* the not-a-font font number                */
  784. X#define    MAX_CHARS    256    /* maximum number of chars in a font         */
  785. X#define SZ_DFT           1000    /* default lout size is 50p                  */
  786. X
  787. X#define font_num(x)        word_font(x)
  788. X#define    font_size(x)        back(x, COL)
  789. X#define    font_xheight2(x)    fwd(x, COL)
  790. X
  791. Xstruct metrics {
  792. X  LENGTH up;
  793. X  LENGTH down;
  794. X  LENGTH left;
  795. X  LENGTH right;
  796. X};
  797. X
  798. Xstatic struct metrics    *size_table[MAX_FONT];    /* metrics of sized fonts    */
  799. Xstatic unsigned char    *lig_table[MAX_FONT];    /* ligatures                 */
  800. Xstatic OBJECT        font_table[MAX_FONT];    /* record of sized fonts     */
  801. Xstatic OBJECT        font_root;        /* root of tree of fonts     */
  802. Xstatic FONT_NUM        fontcount;        /* number of sized fonts     */
  803. X
  804. Xstatic FILE    *out_fp;        /* output file                       */
  805. Xstatic short    currentfont;        /* font of most recent atom          */
  806. Xstatic BOOLEAN    cpexists;        /* true if a current point exists    */
  807. Xstatic LENGTH    currenty;        /* if cpexists, its y coordinate     */
  808. Xstatic int    wordcount;        /* atoms printed since last newline  */
  809. Xstatic int    pagecount;        /* total number of pages printed     */
  810. Xstatic BOOLEAN    prologue_done;        /* TRUE after prologue is printed    */
  811. Xstatic OBJECT    needs;            /* Resource needs of included EPSFs  */
  812. X
  813. X
  814. X/*****************************************************************************/
  815. X/*                                                                           */
  816. X/*  PrintInit(file_ptr)                                                      */
  817. X/*                                                                           */
  818. X/*  Initialise this module.  Output is to go to FILE file_ptr.               */
  819. X/*                                                                           */
  820. X/*****************************************************************************/
  821. X
  822. XPrintInit(file_ptr)
  823. XFILE *file_ptr;
  824. X{ debug0(DFT, D, "PrintInit()");
  825. X  out_fp    = file_ptr;
  826. X  prologue_done    = FALSE;
  827. X  currentfont    = NO_FONT;
  828. X  cpexists    = FALSE;
  829. X  wordcount    = pagecount = 0;
  830. X  fontcount    = 0;
  831. X  font_root    = New(ACAT);
  832. X  needs        = New(ACAT);
  833. X  debug0(DFT, D, "PrintInit returning.");
  834. X}
  835. X
  836. X
  837. X/*****************************************************************************/
  838. X/*                                                                           */
  839. X/*  FontDebug()                                                                 */
  840. X/*                                                                           */
  841. X/*  Print out font tree.                                                     */
  842. X/*                                                                           */
  843. X/*****************************************************************************/
  844. X
  845. X#if DEBUG_ON
  846. Xstatic FontDebug()
  847. X{ OBJECT family, face, filename, link, flink;  int i;
  848. X  assert( font_root != nil && type(font_root)==ACAT, "FontDebug: font_root!" );
  849. X  for( link = Down(font_root);  link != font_root;  link = NextDown(link) )
  850. X  { Child(family, link);
  851. X    assert( type(family) == WORD, "FontDebug: family!" );
  852. X    fprintf(stderr, "family %s:\n", string(family));
  853. X    for( flink = Down(family);  flink != family;  flink = NextDown(flink) )
  854. X    { Child(face, flink);
  855. X      assert( type(face) == WORD, "FontDebug: face!" );
  856. X      fprintf(stderr, "   face %s in file ", string(face));
  857. X      assert( Down(face) != face, "FontDebug: Down(face)!");
  858. X      Child(filename, Down(face));
  859. X      assert( type(filename) == WORD, "FontDebug: filename!" );
  860. X      fprintf(stderr, "%s\n", string(filename));
  861. X    }
  862. X  }
  863. X  for( i = 1;  i <= fontcount;  i++ )
  864. X    fprintf(stderr, "  font_table[%d] = %s\n",
  865. X        i, EchoObject(null, font_table[i]));
  866. X} /* end FontDebug */
  867. X#endif
  868. X
  869. X/*@@**************************************************************************/
  870. X/*                                                                           */
  871. X/*  FontDefine(family, face, filename)                                      */
  872. X/*                                                                           */
  873. X/*  Insert a font with this family, face and file name into the font tree.   */
  874. X/*                                                                           */
  875. X/*****************************************************************************/
  876. X
  877. XFontDefine(family, face, filename)
  878. XOBJECT family, face, filename;
  879. X{ OBJECT link, y;
  880. X  debug3(DFT, D, "FontDefine( %s, %s, %s )",
  881. X    string(family), string(face), string(filename) );
  882. X
  883. X  /* insert family into font tree if not already present */
  884. X  for( link = Down(font_root);  link != font_root;  link = NextDown(link) )
  885. X  { Child(y, link);
  886. X    if( strcmp(string(y), string(family)) == 0 )
  887. X    { Dispose(family);
  888. X      family = y;
  889. X      break;
  890. X    }
  891. X  }
  892. X  if( link == font_root )  Link(font_root, family);
  893. X
  894. X  /* insert face into family, or error if already present */
  895. X  for( link = Down(family);  link != family;  link = NextDown(link) )
  896. X  { Child(y, link);
  897. X    if( strcmp(string(y), string(face)) == 0 )
  898. X    { Error(WARN, &fpos(face), "font %s %s already defined at%s",
  899. X    string(family), string(face), EchoFilePos(&fpos(y)));
  900. X      debug0(DFT, D, "FontDefine returning: font already defined");
  901. X      return;
  902. X    }
  903. X  }
  904. X  Link(family, face);
  905. X
  906. X  assert( type(filename) == WORD, "FontDefine: filename!" );
  907. X  Link(face, filename);
  908. X  Child(filename, Down(face));
  909. X  assert( type(filename) == WORD, "FontDefine: filename!" );
  910. X  debug0(DFT, D, "FontDefine returning.");
  911. X  /* ifdebug(DFT, DD, FontDebug()); */
  912. X} /* end FontDefine */
  913. X
  914. X
  915. X/*@@**************************************************************************/
  916. X/*                                                                           */
  917. X/*  static ReadFont(face, err)                                               */
  918. X/*                                                                           */
  919. X/*  Read in a font file.  Object err is used only for error reporting.       */
  920. X/*                                                                           */
  921. X/*****************************************************************************/
  922. X
  923. X#define is_letter(ch) ( ((ch)>='A' && (ch)<='Z') || ((ch)>='a' && (ch)<='z') )
  924. X
  925. Xstatic int find_ch(str, char_name)
  926. Xunsigned char *str;  OBJECT char_name[];
  927. X{ int i;
  928. X  for( i = 0;  i < MAX_CHARS;  i++ )
  929. X    if( char_name[i] != nil && strcmp(string(char_name[i]), str) == 0 )
  930. X      return i;
  931. X  return -1;
  932. X} /* end find_ch */
  933. X
  934. Xstatic ReadFont(face, err)
  935. XOBJECT face, err;
  936. X{ OBJECT filename, fontname;
  937. X  unsigned char buff[MAX_LINE], command[MAX_LINE];
  938. X  int wx, llx, lly, urx, ury, xheight2, ch, i, lnum, offset;
  939. X  BOOLEAN xhfound, chfound, wxfound, bfound;
  940. X  FILE *fp;
  941. X  struct metrics *fnt;
  942. X  unsigned char *lig;
  943. X  OBJECT char_name[MAX_CHARS], lig_list[MAX_CHARS];
  944. X  OBJECT x, y, z, link, zlink;
  945. X  char *malloc();
  946. X  assert( type(face) == WORD, "ReadFont: type(face) != WORD!" );
  947. X  debug1(DFT, DD, "ReadFont( %s, err )", string(face));
  948. X
  949. X  /* initialize font number and font_table entries, char_name and lig_list */
  950. X  if( ++fontcount >= MAX_FONT )
  951. X     Error(FATAL, &fpos(err), "too many different fonts and sizes (max is %d)",
  952. X       MAX_FONT - 1);
  953. X  for( i = 0;  i < MAX_CHARS;  i++ )  char_name[i] = lig_list[i] = nil;
  954. X
  955. X  /* open Adobe font metrics (.AFM) file */
  956. X  assert( Down(face) != face, "ReadFont: filename missing!" );
  957. X  Child(filename, Down(face));
  958. X  fp = OpenFile(DefineFile(filename, FONT_FILE, FONT_PATH), FALSE);
  959. X  if( fp == NULL )  Error(FATAL, &fpos(filename),
  960. X    "Cannot open font file %s", string(filename));
  961. X  fnt = (struct metrics *) malloc(MAX_CHARS * sizeof(struct metrics));
  962. X  if( ( (unsigned char *) fgets(buff, MAX_LINE, fp) ) != buff ||
  963. X    sscanf(buff, "%s", command) != 1 ||
  964. X    strcmp(command, "StartFontMetrics") != 0 )
  965. X  { Error(FATAL, &fpos(filename),
  966. X      "font file %s does not begin with StartFontMetrics", string(filename));
  967. X  }
  968. X
  969. X  /* read font metrics file */
  970. X  xhfound = FALSE;  fontname = nil;  lnum = 1;
  971. X  while ( ( (unsigned char *) fgets(buff, MAX_LINE, fp) ) == buff )
  972. X  {
  973. X    lnum++;
  974. X    sscanf(buff, "%s", command);
  975. X    switch( command[0] )
  976. X    {
  977. X
  978. X      case 'X':
  979. X
  980. X    if( strcmp(command, "XHeight") == 0 ) 
  981. X    {
  982. X      if( xhfound )
  983. X      { Error(FATAL, &fpos(filename),
  984. X          "XHeight found twice in font file (line %d)", lnum);
  985. X      }
  986. X      sscanf(buff, "XHeight %d", &xheight2);
  987. X      xheight2 = xheight2 / 2;
  988. X      xhfound = TRUE;
  989. X    }
  990. X    break;
  991. X
  992. X
  993. X      case 'F':
  994. X
  995. X    if( strcmp(command, "FontName") == 0 )
  996. X    { if( fontname != nil )
  997. X      { Error(FATAL, &fpos(filename),
  998. X          "FontName found twice in font file %s (line %d)",
  999. X          string(filename), lnum);
  1000. X      }
  1001. X      sscanf(buff, "FontName %s", command);
  1002. X      fontname = MakeWord(command, &fpos(filename));
  1003. X      if( string(fontname)[0] == '\0' )
  1004. X      { Error(FATAL, &fpos(filename),
  1005. X          "FontName empty in font file %s (line %d)",
  1006. X          string(filename), lnum);
  1007. X      }
  1008. X    }
  1009. X    break;
  1010. X
  1011. X
  1012. X      case 'S':
  1013. X
  1014. X    if( strcmp(command, "StartCharMetrics") == 0 )
  1015. X    {
  1016. X      if( fontname == nil )  Error(FATAL, &fpos(filename),
  1017. X        "FontName missing in file %s", string(filename));
  1018. X      if( !xhfound )  xheight2 = DEFAULT_XHEIGHT / 2;
  1019. X      while( ( (unsigned char *) fgets(buff, MAX_LINE, fp) ) == buff )
  1020. X      {
  1021. X        debug1(DFT, DD, "ReadFont reading %s", buff);
  1022. X        lnum++;
  1023. X        sscanf(buff, "%s", command);
  1024. X        if( strcmp(command, "EndCharMetrics") == 0 )
  1025. X        {
  1026. X          /* make a new font record and insert into font tree */
  1027. X          font_size(fontname) = SZ_DFT;
  1028. X          font_xheight2(fontname) = xheight2;
  1029. X          font_num(fontname) = fontcount;
  1030. X          font_table[fontcount] = fontname;
  1031. X          size_table[fontcount] = fnt;
  1032. X          Link(face, fontname);
  1033. X
  1034. X          /* construct ligature table */
  1035. X          ifdebug(DFT, D,
  1036. X        fprintf(stderr, "Ligatures for font %s\n", string(filename));
  1037. X            for( i = 0;  i < MAX_CHARS;  i++ )
  1038. X            { fprintf(stderr, "%3d (%c) %s:\t", i, is_letter(i) ? i : '?',
  1039. X            char_name[i] != nil ? string(char_name[i])
  1040. X                        : (unsigned char *) "<nil>" );
  1041. X          x = lig_list[i];
  1042. X          if( x != nil )
  1043. X          for( link = Down(x);  link != x;  link = NextDown(link) )
  1044. X          { fprintf(stderr, " L ");
  1045. X            Child(y, link);
  1046. X            for( zlink= Down(y);  zlink != y;  zlink = NextDown(zlink) )
  1047. X            { Child(z, zlink);
  1048. X              fprintf(stderr, " %s", string(z));
  1049. X            }
  1050. X            fprintf(stderr, " ;");
  1051. X          }
  1052. X          fprintf(stderr, "\n");
  1053. X            }
  1054. X          );
  1055. X          lig = (unsigned char *) malloc(2*MAX_CHARS);
  1056. X          if( lig == NULL )  Error(FATAL, &fpos(filename),
  1057. X        "run out of memory reading font file %s", string(filename));
  1058. X          for( i = 0;  i < MAX_CHARS;  i++ )  lig[i] = 0;
  1059. X          offset = MAX_CHARS+1;
  1060. X          for( ch = 0;  ch < MAX_CHARS;  ch++ )
  1061. X          { if( lig_list[ch] == nil )  continue;
  1062. X        lig[ch] = offset - MAX_CHARS;
  1063. X        for( link = Down(lig_list[ch]);  link != lig_list[ch];  link =
  1064. X            NextDown(link) )
  1065. X        { lig[offset++] = ch;
  1066. X          Child(y, link);
  1067. X          for( zlink = Down(y);  zlink != y;  zlink = NextDown(zlink) )
  1068. X          { Child(z, zlink);
  1069. X            if( offset >= 2*MAX_CHARS-3 )  Error(FATAL, &fpos(filename),
  1070. X            "too many ligatures in font file %s", string(filename));
  1071. X            i = find_ch(string(z), char_name);
  1072. X            if( i == -1 )  Error(FATAL, &fpos(filename),
  1073. X            "unknown character name %s in font file %s", string(z),
  1074. X            string(filename));
  1075. X            lig[offset++] = i;
  1076. X          }
  1077. X          lig[offset++] = '\0';
  1078. X        }
  1079. X        lig[offset++] = '\0';
  1080. X          }
  1081. X          lig_table[fontcount] = lig;
  1082. X
  1083. X          /* debug and exit */
  1084. X          fclose(fp);
  1085. X          for( i = 0;  i < MAX_CHARS;  i++ )
  1086. X          {    if( char_name[i] != nil )  Dispose(char_name[i]);
  1087. X        if( lig_list[i] != nil )  DisposeObject(lig_list[i]);
  1088. X          }
  1089. X          debug4(DFT, D, "ReadFont returning: %d, name %s, fs %d, xh2 %d",
  1090. X        fontcount, string(fontname), font_size(fontname), xheight2);
  1091. X          return;
  1092. X        }
  1093. X        ch = -1;  
  1094. X        chfound = wxfound = bfound = FALSE;
  1095. X        i = 0;  while( buff[i] == ' ' )  i++;
  1096. X        while( buff[i] != '\n' )
  1097. X        {
  1098. X          sscanf(&buff[i], "%s", command);
  1099. X          if( strcmp(command, "C") == 0 )
  1100. X          {    sscanf(&buff[i], "C %d", &ch);
  1101. X        chfound = TRUE;
  1102. X          }
  1103. X          if( strcmp(command, "N") == 0 )
  1104. X          { if( !chfound )  Error(FATAL, &fpos(filename),
  1105. X          "N precedes C in font file %s (line %d)",
  1106. X          string(filename), lnum);
  1107. X        sscanf(&buff[i], "N %s", command);
  1108. X        char_name[ch] = MakeWord(command, no_fpos);
  1109. X          }
  1110. X          else if( strcmp(command, "WX") == 0 )
  1111. X          {    sscanf(&buff[i], "WX %d", &wx);
  1112. X        wxfound = TRUE;
  1113. X          }
  1114. X          else if( strcmp(command, "B") == 0 )
  1115. X          { sscanf(&buff[i], "B %d %d %d %d", &llx, &lly, &urx, &ury);
  1116. X        bfound = TRUE;
  1117. X          }
  1118. X          else if( strcmp(command, "L") == 0 )
  1119. X          { if( !chfound )  Error(FATAL, &fpos(filename),
  1120. X          "L precedes C in font file %s (line %d)",
  1121. X          string(filename), lnum);
  1122. X        if( lig_list[ch] == nil )  lig_list[ch] = New(ACAT);
  1123. X        y = New(ACAT);
  1124. X        Link(lig_list[ch], y);
  1125. X        i++; /* skip L */
  1126. X        while( buff[i] == ' ' )  i++;
  1127. X        while( buff[i] != ';' && buff[i] != '\n' )
  1128. X        { sscanf(&buff[i], "%s", command);
  1129. X          z = MakeWord(command, no_fpos);
  1130. X          Link(y, z);
  1131. X          while( buff[i] != ' ' && buff[i] != ';' )  i++;
  1132. X          while( buff[i] == ' ' ) i++;
  1133. X        }
  1134. X          }
  1135. X          while( buff[i] != ';' && buff[i] != '\n' )  i++;
  1136. X          if( buff[i] == ';' )
  1137. X          { i++;  while( buff[i] == ' ' ) i++;
  1138. X          }
  1139. X        }
  1140. X        if( !chfound )
  1141. X        { Error(FATAL, &fpos(filename),
  1142. X          "C missing in font file %s (line %d)", string(filename), lnum);
  1143. X        }
  1144. X        if( !wxfound )
  1145. X        { Error(FATAL, &fpos(filename),
  1146. X         "WX missing in font file %s (line %d)", string(filename), lnum);
  1147. X        }
  1148. X        if( !bfound )
  1149. X        { Error(FATAL, &fpos(filename),
  1150. X          "B missing in font file %s (line %d)", string(filename), lnum);
  1151. X        }
  1152. X        if( ch >= 0 && ch < MAX_CHARS )
  1153. X        { fnt[ch].left  = llx;
  1154. X          fnt[ch].down  = lly - xheight2;
  1155. X          fnt[ch].right = wx;
  1156. X          fnt[ch].up    = ury - xheight2;
  1157. X          debug5(DFT, DD, "  fnt[%c] = (%d,%d,%d,%d)", ch, fnt[ch].left,
  1158. X        fnt[ch].down, fnt[ch].right, fnt[ch].up);
  1159. X        }
  1160. X      }
  1161. X      Error(FATAL, &fpos(filename),
  1162. X        "EndCharMetrics missing from font file %s", string(filename));
  1163. X    }
  1164. X    break;
  1165. X
  1166. X
  1167. X      default:
  1168. X
  1169. X    break;
  1170. X
  1171. X    }
  1172. X  }
  1173. X  Error(FATAL, &fpos(filename),
  1174. X    "StartCharMetrics missing from font file %s", string(filename));
  1175. X} /* end ReadFont */
  1176. X
  1177. X
  1178. X/*@@**************************************************************************/
  1179. X/*                                                                           */
  1180. X/*  FontChange(style, x)                                                     */
  1181. X/*                                                                           */
  1182. X/*  Returns an internal font number which is the current font changed        */
  1183. X/*  according to word object x.  e.g. if current font is Roman 12p and x is  */
  1184. X/*  "-3p", then FontChange returns the internal font number of Roman 9p.     */
  1185. X/*                                                                           */
  1186. X/*****************************************************************************/
  1187. X
  1188. XFontChange(style, x)
  1189. XSTYLE *style;  OBJECT x;
  1190. X{ /* register */ int i;
  1191. X  OBJECT par[3], family, face, fsize, y, link, new, old, tmpf;
  1192. X  GAP gp;  LENGTH flen;  int num, c;  unsigned inc;
  1193. X  struct metrics *newfnt, *oldfnt;  char *malloc();
  1194. X  debug2(DFT, D, "FontChange( %s, %s )", EchoStyle(style), EchoObject(null, x));
  1195. X  assert( font(*style)>=0 && font(*style)<=fontcount, "FontChange: fontcount!");
  1196. X  /* ifdebug(DFT, DD, FontDebug()); */
  1197. X
  1198. X  /* set par[0..num-1] to the 1, 2 or 3 parameters of the font operator */
  1199. X  num = 0;
  1200. X  if( type(x) == WORD )
  1201. X  { par[num++] = x;
  1202. X    FontStripQuotes(string(x), &fpos(x));
  1203. X  }
  1204. X  else if( type(x) == ACAT )
  1205. X  { for( link = Down(x);  link != x;  link = NextDown(link) )
  1206. X    { Child(y, link);
  1207. X      debug1(DFT, DD, "  pars examining y = %s", EchoObject(null, y));
  1208. X      if( type(y) == GAP_OBJ )  continue;
  1209. X      if( type(y) != WORD || num >= 3 )
  1210. X      {    Error(WARN, &fpos(x), "error in left parameter of %s", KW_FONT);
  1211. X    debug0(DFT, D, "FontChange returning: ACAT children");
  1212. X    return;
  1213. X      }
  1214. X      par[num++] = y;
  1215. X      FontStripQuotes(string(y), &fpos(x));
  1216. X    }
  1217. X  }
  1218. X  else
  1219. X  { Error(WARN, &fpos(x), "error in left parameter of %s", KW_FONT);
  1220. X    debug0(DFT, D, "FontChange returning: wrong type");
  1221. X    return;
  1222. X  }
  1223. X  debug1(DFT, DD, " found pars, num = %d", num);
  1224. X
  1225. X  /* extract fsize parameter, if any */
  1226. X  assert( num >= 1 && num <= 3, "FontChange: num!" );
  1227. X  c = string(par[num-1])[0];
  1228. X  if( c == '+' || c == '-' || (c >= '0' && c <= '9') )
  1229. X  { fsize = par[num-1];  num--;
  1230. X  }
  1231. X  else fsize = nil;
  1232. X
  1233. X  /* check for initial font case: must have family, face, and size */
  1234. X  if( font(*style) == NO_FONT && (fsize == nil || num < 2) )
  1235. X    Error(FATAL, &fpos(x), "initial font must have family, face and size");
  1236. X
  1237. X  /* get font family */
  1238. X  if( num == 2 )
  1239. X  {
  1240. X    /* par[0] contains a new family name */
  1241. X    for( link = Down(font_root);  link != font_root;  link = NextDown(link) )
  1242. X    { Child(family, link);
  1243. X      if( strcmp(string(family), string(par[0])) == 0 )  break;
  1244. X    }
  1245. X    if( link == font_root )
  1246. X    { Error(WARN,&fpos(par[0]), "font family %s not defined", string(par[0]));
  1247. X      return;
  1248. X    }
  1249. X  }
  1250. X  else
  1251. X  { /* preserve current family */
  1252. X    assert( Up(font_table[font(*style)]) != font_table[font(*style)],
  1253. X      "FontChange: Up(font_table[font(*style)]) !" );
  1254. X    Parent(face, Up(font_table[font(*style)]));
  1255. X    assert( type(face) == WORD, "FontChange: type(face)!" );
  1256. X    assert( Up(face) != face, "FontChange: Up(face)!" );
  1257. X    Parent(family, Up(face));
  1258. X    assert( type(family) == WORD, "FontChange: type(family)!" );
  1259. X  }
  1260. X
  1261. X  /* get font face */
  1262. X  if( num != 0 )
  1263. X  {
  1264. X    /* par[num-1] contains a new face name */
  1265. X    for( link = Down(family);  link != family;  link = NextDown(link) )
  1266. X    { Child(face, link);
  1267. X      if( strcmp(string(face), string(par[num-1])) == 0 )  break;
  1268. X    }
  1269. X    if( link == family )
  1270. X    {
  1271. X      /* missing face name; first check whether a family name was intended */
  1272. X      for( link = Down(font_root);  link != font_root;  link = NextDown(link) )
  1273. X      {    Child(tmpf, link);
  1274. X    if( strcmp(string(tmpf), string(par[num-1])) == 0 )  break;
  1275. X      }
  1276. X      if( font_root == Down(font_root) )
  1277. X      {    Error(FATAL, &fpos(par[num-1]), "there are no fonts");
  1278. X      }
  1279. X      else if( link != font_root )
  1280. X      {    Error(WARN, &fpos(par[num-1]),
  1281. X        "font family name %s must be accompanied by a face name",
  1282. X        string(par[num-1]));
  1283. X      }
  1284. X      else Error(WARN, &fpos(par[num-1]),
  1285. X        "font face name %s not defined in font family %s",
  1286. X        string(par[num-1]), string(family));
  1287. X      return;
  1288. X    }
  1289. X  }
  1290. X  else
  1291. X  {
  1292. X    /* preserve current face name */
  1293. X    Parent(face, Up(font_table[font(*style)]));
  1294. X    assert( type(face) == WORD, "FontChange: type(face)!" );
  1295. X    assert( Up(face) != face, "FontChange: Up(face)!" );
  1296. X  }
  1297. X
  1298. X  /* get font size */
  1299. X  if( fsize == nil )  flen = font_size(font_table[font(*style)]);
  1300. X  else 
  1301. X  { GetGap(fsize, style, &gp, &inc);
  1302. X    if( inc == ABS )  flen = width(gp);
  1303. X    else if( font(*style) == NO_FONT )
  1304. X      Error(FATAL, &fpos(fsize), "no font encloses this %s", string(fsize));
  1305. X    else if( inc==INC )  flen = font_size(font_table[font(*style)])+width(gp);
  1306. X    else if( inc==DEC )  flen = font_size(font_table[font(*style)])-width(gp);
  1307. X    else Error(INTERN, &fpos(x), "GetGap returned inc = %d!", inc);
  1308. X  }
  1309. X
  1310. X  if( flen <= 0 )
  1311. X  { Error(WARN, &fpos(fsize), "%s %s ignored: result is not positive",
  1312. X      string(fsize), KW_FONT);
  1313. X    return;
  1314. X  }
  1315. X
  1316. X  /* if the font file has not been read before, read it now */
  1317. X  assert( Down(face) != face && type(Down(face)) == LINK, "FontChange: dn!" );
  1318. X  if( Down(face) == LastDown(face) )  ReadFont(face, x);
  1319. X  assert( Down(face) != LastDown(face), "FontChange: after ReadFont!" );
  1320. X
  1321. X  /* search fonts of face for desired size; return if already present */
  1322. X  for( link = NextDown(Down(face));  link != face;  link = NextDown(link) )
  1323. X  { Child(fsize, link);
  1324. X    if( font_size(fsize) == flen )
  1325. X    { font(*style) = font_num(fsize);
  1326. X      SetGap( space_gap(*style), FALSE, TRUE, FIXED_UNIT, EDGE_MODE,
  1327. X            size_table[font_num(fsize)][' '].right);
  1328. X      debug2(DFT, D,"FontChange returning (old) %d (XHeight2 = %d)",
  1329. X            font(*style), font_xheight2(font_table[font(*style)]));
  1330. X      return;
  1331. X    }
  1332. X  }
  1333. X
  1334. X  /* insert new sized font record into tree */
  1335. X  if( ++fontcount >= MAX_FONT )
  1336. X    Error(FATAL, &fpos(x), "too many different fonts and sizes (max is %d)",
  1337. X      MAX_FONT - 1);
  1338. X  assert( Down(face) != face && NextDown(Down(face)) != face, "FontChange!!" );
  1339. X  Child(old, NextDown(Down(face)));
  1340. X  assert( type(old) == WORD, "FontChange: old!" );
  1341. X  new = MakeWord(string(old), no_fpos);
  1342. X  Link(face, new);
  1343. X  font_size(new)        = flen;
  1344. X  font_xheight2(new)    = font_xheight2(old) * font_size(new) / font_size(old);
  1345. X  font_num(new)         = fontcount;
  1346. X  font_table[fontcount] = new;
  1347. X  size_table[fontcount] =
  1348. X    (struct metrics *) malloc(MAX_CHARS * sizeof(struct metrics));
  1349. X  lig_table[fontcount]  = (unsigned char *) malloc(2*MAX_CHARS);
  1350. X
  1351. X  /* scale old font to new size */
  1352. X  newfnt = size_table[font_num(new)];
  1353. X  oldfnt = size_table[font_num(old)];
  1354. X  for( i = 0;  i < MAX_CHARS;  i++ )
  1355. X  { newfnt[i].left  = (oldfnt[i].left  * font_size(new)) / font_size(old);
  1356. X    newfnt[i].right = (oldfnt[i].right * font_size(new)) / font_size(old);
  1357. X    newfnt[i].down  = (oldfnt[i].down  * font_size(new)) / font_size(old);
  1358. X    newfnt[i].up    = (oldfnt[i].up    * font_size(new)) / font_size(old);
  1359. X  }
  1360. X  for( i = 0;  i < 2*MAX_CHARS;  i++ )
  1361. X    lig_table[font_num(new)][i] = lig_table[font_num(old)][i];
  1362. X
  1363. X  /* return new font number and exit */
  1364. X  font(*style) = fontcount;
  1365. X  SetGap( space_gap(*style), FALSE, TRUE, FIXED_UNIT, EDGE_MODE,
  1366. X    size_table[fontcount][' '].right);
  1367. X  debug2(DFT, D,"FontChange returning (scaled) %d (XHeight2 = %d)",
  1368. X    font(*style), font_xheight2(font_table[font(*style)]));
  1369. X  /* FontDebug(); */
  1370. X} /* end FontChange */
  1371. X
  1372. X/*@@**************************************************************************/
  1373. X/*                                                                           */
  1374. X/*  FontAtomSize(x)                                                          */
  1375. X/*                                                                           */
  1376. X/*  Set the horizontal and vertical sizes of literal atom x.                 */
  1377. X/*                                                                           */
  1378. X/*****************************************************************************/
  1379. X
  1380. XFontAtomSize(x)
  1381. XOBJECT x;
  1382. X{ 
  1383. X  /* register */ unsigned char *p;
  1384. X  /* register */ int r, u, d, ch, newch;
  1385. X  struct metrics *fnt;  unsigned char *lig;
  1386. X
  1387. X  debug2(DFT, D, "FontAtomSize( %s ), font = %d", string(x), word_font(x));
  1388. X  FirstChar(string(x), ch, &fpos(x));
  1389. X  debug1(DFT, DDD, "  ch = %d", ch);
  1390. X  if( ch == '\0' )
  1391. X  { back(x, COL) = fwd(x, COL) = 0;
  1392. X    back(x, ROW) = fwd(x, ROW) = 0;
  1393. X  }
  1394. X  else
  1395. X  { if ( word_font(x) < 1 || word_font(x) > fontcount )
  1396. X      Error(FATAL, &fpos(x), "%s operator missing, word is %s",
  1397. X    KW_FONT, string(x));
  1398. X    fnt = size_table[word_font(x)];
  1399. X    lig = lig_table[word_font(x)];
  1400. X    CheckLigature(string(x), ch, lig);
  1401. X    d = fnt[ch].down;
  1402. X    u = fnt[ch].up;
  1403. X    r = fnt[ch].right;
  1404. X    NextChar(string(x), ch, &fpos(x));
  1405. X    CheckLigature(string(x), ch, lig);
  1406. X    debug1(DFT, DDD, "  ch = %d", ch);
  1407. X    while( ch )
  1408. X    { if( fnt[ch].up   > u )  u = fnt[ch].up;
  1409. X      if( fnt[ch].down < d )  d = fnt[ch].down;
  1410. X      r += fnt[ch].right;
  1411. X      NextChar(string(x), ch, &fpos(x));
  1412. X      CheckLigature(string(x), ch, lig);
  1413. X      debug1(DFT, DDD, "  ch = %d", ch);
  1414. X    }
  1415. X    back(x, COL) = 0;
  1416. X    fwd(x, COL)  = max(r, 0);
  1417. X    back(x, ROW) = max(u, 0);
  1418. X    fwd(x, ROW)  = max(-d, 0);
  1419. X  } 
  1420. X  debug4(DFT, D, "FontAtomSize returning %hd %hd %hd %hd",
  1421. X      back(x, COL), fwd(x, COL), back(x, ROW), fwd(x, ROW));
  1422. X} /* end FontAtomSize */
  1423. X
  1424. X
  1425. X/*****************************************************************************/
  1426. X/*                                                                           */
  1427. X/*  LENGTH FontSize(fnum, x)                                                 */
  1428. X/*                                                                           */
  1429. X/*  Return the size of this font.  x is for error messages only.             */
  1430. X/*                                                                           */
  1431. X/*****************************************************************************/
  1432. X
  1433. XLENGTH FontSize(fnum, x)
  1434. XFONT_NUM fnum;  OBJECT x;
  1435. X{
  1436. X  debug1(DFT, D, "FontSize( %d )", fnum);
  1437. X  assert( fnum <= fontcount, "FontSize!" );
  1438. X  if( fnum <= 0 )  Error(FATAL, &fpos(x), "no current font at this point");
  1439. X  debug1(DFT, D, "FontSize returning %d", font_size(font_table[fnum]));
  1440. X  return font_size(font_table[fnum]);
  1441. X} /* end FontSize */
  1442. X
  1443. X
  1444. X/*@@**************************************************************************/
  1445. X/*                                                                           */
  1446. X/*  PrintPrologue(h, v)                                                      */
  1447. X/*                                                                           */
  1448. X/*  Generate the standard PostScript prologue, augmented with any @Prologue  */
  1449. X/*  or @SysPrologue files specified by the user.                             */
  1450. X/*  The first non-empty page has width h and height v in Lout units.         */
  1451. X/*  The following PostScript operators are defined:                          */
  1452. X/*                                                                           */
  1453. X/*      scale_factor  fnt       scale and set font                           */
  1454. X/*      x_coordinate  x         move to x_coordinate, current y coordinate   */
  1455. X/*      string        s         show string                                  */
  1456. X/*      number        in        result is number inches                      */
  1457. X/*      number        cm        result is number centimetres                 */
  1458. X/*      number        pt        result is number points                      */
  1459. X/*      number        sp        result is number spaces                      */
  1460. X/*      number        vs        result is number v's                         */
  1461. X/*      number        ft        result is number font-sizes                  */
  1462. X/*                                                                           */
  1463. X/*  as well as loutgr, for use with Lout's @Graphic operator:                */
  1464. X/*                                                                           */
  1465. X/*      xsize ysize xmark ymark fr vs sp loutgr -                            */
  1466. X/*                                                                           */
  1467. X/*  Define xmark, ymark, xsize, ysize to be the positions of                 */
  1468. X/*  these features of x, and define symbols ft, vs and sp                    */
  1469. X/*  to be the current font size, line separation, and space width.           */
  1470. X/*                                                                           */
  1471. X/*****************************************************************************/
  1472. X
  1473. XPrintPrologue(h, v)
  1474. XLENGTH h, v;
  1475. X{ FILE_NUM fnum;
  1476. X  debug2(DGP, DD, "PrintPrologue: v = %d   h = %d", v, h);
  1477. X
  1478. X  /* print header comments for PostScript DSC 3.0 output */
  1479. X  if( Encapsulated )
  1480. X    fprintf(out_fp, "%%%!PS-Adobe-3.0 EPSF-3.0\n");
  1481. X  else
  1482. X    fprintf(out_fp, "%%%!PS-Adobe-3.0\n");
  1483. X  fprintf(out_fp, "%%%%Creator: %s\n", LOUT_VERSION);
  1484. X  fprintf(out_fp, "%%%%CreationDate: %s", TimeString());
  1485. X  fprintf(out_fp, "%%%%DocumentNeededResources: (atend)\n");
  1486. X  fprintf(out_fp, "%%%%Pages: (atend)\n");
  1487. X  fprintf(out_fp, "%%%%BoundingBox: 0 0 %d %d\n", h/PT, v/PT);
  1488. X  fprintf(out_fp, "%%%%EndComments\n");
  1489. X
  1490. X  /* print procedure definitions part of header */
  1491. X  fprintf(out_fp, "%%%%BeginProlog\n");
  1492. X  fprintf(out_fp, "%%%%BeginResource: procset LoutStartUp\n");
  1493. X  fprintf(out_fp, "/fnt { exch findfont exch scalefont setfont } def\n");
  1494. X  fprintf(out_fp, "/x { currentpoint exch pop moveto } def\n");
  1495. X  fprintf(out_fp, "/s { show } def\n");
  1496. X  fprintf(out_fp, "/in { %d mul } def\n", IN);
  1497. X  fprintf(out_fp, "/cm { %d mul } def\n", CM);
  1498. X  fprintf(out_fp, "/pt { %d mul } def\n", PT);
  1499. X  fprintf(out_fp, "/em { %d mul } def\n", EM);
  1500. X  fprintf(out_fp, "/sp { louts mul } def\n");
  1501. X  fprintf(out_fp, "/vs { loutv mul } def\n");
  1502. X  fprintf(out_fp, "/ft { loutf mul } def\n");
  1503. X  fprintf(out_fp, "/dg {           } def\n");
  1504. X
  1505. X  fputs("/loutgr {\n",                        out_fp);
  1506. X  fputs("  /louts exch def\n",                    out_fp);
  1507. X  fputs("  /loutv exch def\n",                    out_fp);
  1508. X  fputs("  /loutf exch def\n",                    out_fp);
  1509. X  fputs("  /ymark exch def\n",                    out_fp);
  1510. X  fputs("  /xmark exch def\n",                    out_fp);
  1511. X  fputs("  /ysize exch def\n",                    out_fp);
  1512. X  fputs("  /xsize exch def\n} def\n",                out_fp);
  1513. X
  1514. X  /* print definitions used by Lout output when including EPSF files */
  1515. X  /* copied from PostScript Language Reference Manual (2nd Ed.), page 726 */
  1516. X  fputs("/BeginEPSF {\n",                    out_fp);
  1517. X  fputs("  /LoutEPSFState save def\n",                out_fp);
  1518. X  fputs("  /dict_count countdictstack def\n",            out_fp);
  1519. X  fputs("  /op_count count 1 sub def\n",            out_fp);
  1520. X  fputs("  userdict begin\n",                    out_fp);
  1521. X  fputs("  /showpage { } def\n",                out_fp);
  1522. X  fputs("  0 setgray 0 setlinecap\n",                out_fp);
  1523. X  fputs("  1 setlinewidth 0 setlinejoin\n",            out_fp);
  1524. X  fputs("  10 setmiterlimit [] 0 setdash newpath\n",        out_fp);
  1525. X  fputs("  /languagelevel where\n",                out_fp);
  1526. X  fputs("  { pop languagelevel\n",                out_fp);
  1527. X  fputs("    1 ne\n",                        out_fp);
  1528. X  fputs("    { false setstrokeadjust false setoverprint\n",    out_fp);
  1529. X  fputs("    } if\n",                        out_fp);
  1530. X  fputs("  } if\n",                        out_fp);
  1531. X  fputs("} bind def\n",                        out_fp);
  1532. X
  1533. X  fputs("/EndEPSF {\n",                        out_fp);
  1534. X  fputs("  count op_count sub { pop } repeat\n",        out_fp);
  1535. X  fputs("  countdictstack dict_count sub { end } repeat\n",    out_fp);
  1536. X  fputs("  LoutEPSFState restore\n",                out_fp);
  1537. X  fputs("} bind def\n",                        out_fp);
  1538. X
  1539. X  fputs("%%EndResource\n",                    out_fp);
  1540. X
  1541. X  /* print prepend files (assumed to be organized as DSC 3.0 Resources) */
  1542. X  for( fnum=FirstFile(PREPEND_FILE);  fnum != NO_FILE;  fnum=NextFile(fnum) )
  1543. X  { char buff[MAX_LINE];  FILE *fp;
  1544. X    if( (fp = OpenFile(fnum, FALSE)) == null )
  1545. X      Error(WARN, PosOfFile(fnum), "cannot open %s file %s",
  1546. X    KW_PREPEND, FileName(fnum));
  1547. X    else if( fgets(buff, MAX_LINE, fp) == NULL )
  1548. X      Error(WARN, PosOfFile(fnum), "%s file %s is empty",
  1549. X    KW_PREPEND, FileName(fnum));
  1550. X    else
  1551. X    {
  1552. X      if( !StringBeginsWith(buff, "%%BeginResource:") )
  1553. X    Error(WARN, PosOfFile(fnum),
  1554. X      "%s file %s lacks PostScript DSC 3.0 \"%%%%BeginResource:\" comment",
  1555. X      KW_PREPEND, FileName(fnum));
  1556. X      fputs(buff, out_fp);
  1557. X      fprintf(out_fp, "\n%% %s file %s\n", KW_PREPEND, FileName(fnum));
  1558. X      while( fgets(buff, MAX_LINE, fp) != NULL )  fputs(buff, out_fp);
  1559. X    }
  1560. X  }
  1561. X
  1562. X  fputs("\n%%EndProlog\n\n", out_fp);
  1563. X  fprintf(out_fp, "%%%%Page: ? %d\n", ++pagecount);
  1564. X  fprintf(out_fp, "%%%%BeginPageSetup\n");
  1565. X  fprintf(out_fp, "%.4f dup scale %d setlinewidth\n", 1.0 / PT, PT/2);
  1566. X  fprintf(out_fp, "/pgsave save def\n");
  1567. X  fprintf(out_fp, "%%%%EndPageSetup\n");
  1568. X  prologue_done = TRUE;
  1569. X} /* end PrintPrologue */
  1570. X
  1571. X/*@@**************************************************************************/
  1572. X/*                                                                           */
  1573. X/*  PrintOriginIncrement(y)                                                  */
  1574. X/*                                                                           */
  1575. X/*  Move current vertical origin down by y.                                  */
  1576. X/*                                                                           */
  1577. X/*****************************************************************************/
  1578. X
  1579. XPrintOriginIncrement(y)
  1580. XLENGTH y;
  1581. X{ debug1(DGP, D, "PrintOriginIncrement( %d )", y );
  1582. X  fprintf(out_fp, "\npgsave restore\nshowpage\n");
  1583. X  cpexists = FALSE;
  1584. X  currentfont = NO_FONT;
  1585. X  if( Encapsulated )
  1586. X  { PrintClose();
  1587. X    Error(FATAL, no_fpos, "truncating -EPS document at end of first page");
  1588. X  }
  1589. X  fprintf(out_fp, "\n%%%%Page: ? %d\n", ++pagecount);
  1590. X  fprintf(out_fp, "%%%%BeginPageSetup\n");
  1591. X  fprintf(out_fp, "%.4f dup scale %d setlinewidth\n", 1.0 / PT, PT/2);
  1592. X  fprintf(out_fp, "/pgsave save def\n");
  1593. X  fprintf(out_fp, "%%%%EndPageSetup\n");
  1594. X  wordcount = 0;
  1595. X}
  1596. X
  1597. X
  1598. X/*****************************************************************************/
  1599. X/*                                                                           */
  1600. X/*  PrintAtom(x, hpos, vpos)                                                 */
  1601. X/*                                                                           */
  1602. X/*  Print word x; its marks cross at the point (hpos, vpos).                 */
  1603. X/*                                                                           */
  1604. X/*****************************************************************************/
  1605. X
  1606. XPrintAtom(x, hpos, vpos)
  1607. XOBJECT x;  int hpos, vpos;
  1608. X{ unsigned char *p;
  1609. X
  1610. X  debug4(DGP, DD, "PrintAtom( %s, %d, %d ) font %d", string(x),
  1611. X    hpos, vpos, word_font(x));
  1612. X
  1613. X  /* if font is different to previous word then print change */
  1614. X  if (word_font(x) != currentfont)
  1615. X  { currentfont = word_font(x);
  1616. X    assert( type(font_table[currentfont])==WORD, "PrintAtom: font_table!" );
  1617. X    if( string(font_table[currentfont])[0] == '\0' )
  1618. X    { Error(INTERN, &fpos(font_table[currentfont]),
  1619. X    "font bug: font %d, addr %d, string addr %d (hex 0x%x)",
  1620. X    currentfont, font_table[currentfont],
  1621. X    string(font_table[currentfont]), string(font_table[currentfont]));
  1622. X    }
  1623. X    fprintf(out_fp, "\n/%s %hd fnt\n",
  1624. X      string(font_table[currentfont]), font_size(font_table[currentfont]));
  1625. X  }
  1626. X
  1627. X  /* move to coordinate of x */
  1628. X  debug1(DGP, DDD, "  xheight2 = %d", font_xheight2(font_table[currentfont]));
  1629. X  vpos = vpos - font_xheight2(font_table[currentfont]);
  1630. X  if( cpexists && currenty == vpos )
  1631. X  { printnum(hpos, out_fp);
  1632. X    fputs(" x", out_fp);
  1633. X  }
  1634. X  else
  1635. X  { currenty = vpos;
  1636. X    printnum(hpos, out_fp);
  1637. X    putc(' ', out_fp);
  1638. X    printnum(currenty, out_fp);
  1639. X    fputs(" moveto", out_fp);
  1640. X    cpexists = TRUE;
  1641. X  }
  1642. X
  1643. X  /* show string(x) */
  1644. X  putc('(', out_fp);
  1645. X  p = string(x);
  1646. X  while( *p != '\0' )  switch( *p )
  1647. X  {
  1648. X    case '"':    p++;
  1649. X        break;
  1650. X
  1651. X    case '\\':    switch( *++p )
  1652. X        {
  1653. X          case '\0':    break;
  1654. X      
  1655. X          case '"':    putc(*p++, out_fp);
  1656. X                break;
  1657. X
  1658. X          case '\\':
  1659. X          case '0':
  1660. X          case '1':
  1661. X          case '2':
  1662. X          case '3':
  1663. X          case '4':
  1664. X          case '5':
  1665. X          case '6':
  1666. X          case '7':    putc('\\', out_fp);
  1667. X                putc(*p++,   out_fp);
  1668. X                break;
  1669. X
  1670. X          default:    /* denotes print in octal e.g. ligature */
  1671. X                putc('\\', out_fp);
  1672. X                fprintf(out_fp, "%03o", *p++);
  1673. X        }
  1674. X        break;
  1675. X
  1676. X    case '(':    
  1677. X    case ')':    putc('\\', out_fp);
  1678. X        putc(*p++, out_fp);
  1679. X        break;
  1680. X
  1681. X    default:    putc(*p++, out_fp);
  1682. X        break;
  1683. X  }
  1684. X  if( ++wordcount >= 5 )
  1685. X  { fputs(")s\n", out_fp);  wordcount = 0;
  1686. X  }
  1687. X  else fputs(")s ", out_fp);
  1688. X
  1689. X  debug0(DGP, DDD, "PrintAtom returning");
  1690. X} /* end PrintAtom */
  1691. X
  1692. X
  1693. X/*@@**************************************************************************/
  1694. X/*                                                                           */
  1695. X/*  PrintClose()                                                             */
  1696. X/*                                                                           */
  1697. X/*  Clean up this module and close output stream.                            */
  1698. X/*                                                                           */
  1699. X/*****************************************************************************/
  1700. X
  1701. XPrintClose()
  1702. X{ OBJECT family, face, x, link, flink;  BOOLEAN first_need;
  1703. X  if( prologue_done )
  1704. X  { fprintf(out_fp, "\npgsave restore\nshowpage\n");
  1705. X    fprintf(out_fp, "%%%%Trailer\n");
  1706. X
  1707. X    /* print document fonts line */
  1708. X    /* *** obsolete DSC 1.0 version
  1709. X    fprintf(out_fp, "%%%%DocumentFonts:");
  1710. X    for( link = Down(font_root); link != font_root; link = NextDown(link) )
  1711. X    { Child(family, link);
  1712. X      for( flink = Down(family);  flink != family;  flink = NextDown(flink) )
  1713. X      {    Child(face, flink);
  1714. X    if( LastDown(face) != Down(face) )
  1715. X    { Child(x, LastDown(face));
  1716. X      fprintf(out_fp, " %s", string(x));
  1717. X    }
  1718. X      }
  1719. X    }
  1720. X    fprintf(out_fp, "\n");
  1721. X    *** */
  1722. X
  1723. X    /* print resource requirements (DSC 3.0 version) - fonts */
  1724. X    first_need = TRUE;
  1725. X    for( link = Down(font_root); link != font_root; link = NextDown(link) )
  1726. X    { Child(family, link);
  1727. X      for( flink = Down(family);  flink != family;  flink = NextDown(flink) )
  1728. X      { Child(face, flink);
  1729. X    if( LastDown(face) != Down(face) )
  1730. X    { Child(x, LastDown(face));
  1731. X      fprintf(out_fp, "%s font %s\n",
  1732. X        first_need ? "%%DocumentNeededResources:" : "%%+", string(x));
  1733. X      first_need = FALSE;
  1734. X    }
  1735. X      }
  1736. X    }
  1737. X
  1738. X    /* print resource requirements (DSC 3.0 version) - included EPSFs  */
  1739. X    for( link = Down(needs); link != needs; link = NextDown(link) )
  1740. X    { Child(x, link);
  1741. X      assert(type(x) == WORD, "PrintClose: needs!" );
  1742. X      fprintf(out_fp, "%s %s",
  1743. X    first_need ? "%%DocumentNeededResources:" : "%%+", string(x));
  1744. X      first_need = FALSE;
  1745. X    }
  1746. X
  1747. X    fprintf(out_fp, "%%%%Pages: %d\n", pagecount);
  1748. X    fprintf(out_fp, "%%%%EOF\n");
  1749. X  }
  1750. X  DisposeObject(font_root);
  1751. X} /* end PrintClose */
  1752. X
  1753. X
  1754. X/*****************************************************************************/
  1755. X/*                                                                           */
  1756. X/*  CoordTranslate(xdist, ydist)                                             */
  1757. X/*                                                                           */
  1758. X/*  Translate coordinate system by the given x and y distances.              */
  1759. X/*                                                                           */
  1760. X/*****************************************************************************/
  1761. X
  1762. XCoordTranslate(xdist, ydist)
  1763. XLENGTH xdist, ydist;
  1764. X{ debug2(DRS,D,"CoordTranslate(%s, %s)",
  1765. X    EchoLength(xdist), EchoLength(ydist));
  1766. X  fprintf(out_fp, "%d %d translate\n", xdist, ydist);
  1767. X  cpexists = FALSE;
  1768. X  currentfont = NO_FONT;
  1769. X  debug0(DRS, D, "CoordTranslate returning.");
  1770. X} /* end CoordTranslate */
  1771. X
  1772. X
  1773. X/*@@**************************************************************************/
  1774. X/*                                                                           */
  1775. X/*  CoordRotate(amount)                                                      */
  1776. X/*                                                                           */
  1777. X/*  Rotate coordinate system by given amount (in internal DG units)          */
  1778. X/*                                                                           */
  1779. X/*****************************************************************************/
  1780. X
  1781. XCoordRotate(amount)
  1782. XLENGTH amount;
  1783. X{ debug1(DRS, D, "CoordRotate(%.1f degrees)", (float) amount / DG);
  1784. X  fprintf(out_fp, "%.4f rotate\n", (float) amount / DG);
  1785. X  cpexists = FALSE;
  1786. X  currentfont = NO_FONT;
  1787. X  debug0(DRS, D, "CoordRotate returning.");
  1788. X} /* end CoordRotate */
  1789. X
  1790. X
  1791. X/*****************************************************************************/
  1792. X/*                                                                           */
  1793. X/*  CoordScale(ratio, dim)                                                   */
  1794. X/*                                                                           */
  1795. X/*  Scale coordinate system by ratio in the given dimension.                 */
  1796. X/*                                                                           */
  1797. X/*****************************************************************************/
  1798. X
  1799. XCoordScale(hfactor, vfactor)
  1800. Xfloat hfactor, vfactor;
  1801. X{ unsigned char buff[20];
  1802. X  ifdebug(DRS, D, sprintf(buff, "%.3f, %.3f", hfactor, vfactor));
  1803. X  debug1(DRS, D, "CoordScale(%s)", buff);
  1804. X  fprintf(out_fp, "%.4f %.4f scale\n", hfactor, vfactor);
  1805. X  cpexists = FALSE;
  1806. X  currentfont = NO_FONT;
  1807. X  debug0(DRS, D, "CoordScale returning.");
  1808. X} /* end CoordScale */
  1809. X
  1810. X
  1811. X/*****************************************************************************/
  1812. X/*                                                                           */
  1813. X/*  SaveGraphicState()                                                       */
  1814. X/*                                                                           */
  1815. X/*  Save current coord system on stack for later restoration.                */
  1816. X/*                                                                           */
  1817. X/*****************************************************************************/
  1818. X
  1819. XSaveGraphicState()
  1820. X{ debug0(DRS, D, "SaveGraphicState()");
  1821. X  fprintf(out_fp, "gsave\n");
  1822. X  debug0(DRS, D, "SaveGraphicState returning.");
  1823. X} /* end SaveGraphicState */
  1824. X
  1825. X
  1826. X/*****************************************************************************/
  1827. X/*                                                                           */
  1828. X/*  RestoreGraphicState()                                                    */
  1829. X/*                                                                           */
  1830. X/*  Restore previously saved coordinate system.  NB we normally assume that  */
  1831. X/*  no white space is needed before any item of output, but since this       */
  1832. X/*  procedure is sometimes called immediately after PrintGraphicObject(),    */
  1833. X/*  which does not append a concluding space, we prepend one here.           */
  1834. X/*                                                                           */
  1835. X/*****************************************************************************/
  1836. X
  1837. XRestoreGraphicState()
  1838. X{ debug0(DRS, D, "RestoreGraphicState()");
  1839. X  fprintf(out_fp, "\ngrestore\n");
  1840. X  cpexists = FALSE;
  1841. X  currentfont = NO_FONT;
  1842. X  debug0(DRS, D, "RestoreGraphicState returning.");
  1843. X} /* end RestoreGraphicState */
  1844. X
  1845. X
  1846. X/*@@**************************************************************************/
  1847. X/*                                                                           */
  1848. X/*  PrintGraphicObject(x)                                                    */
  1849. X/*                                                                           */
  1850. X/*  Print object x on out_fp                                                 */
  1851. X/*                                                                           */
  1852. X/*****************************************************************************/
  1853. X
  1854. XPrintGraphicObject(x)
  1855. XOBJECT x;
  1856. X{ OBJECT y, link;  unsigned char *p;
  1857. X  switch( type(x) )
  1858. X  {
  1859. X    case WORD:
  1860. X    
  1861. X      for( p = string(x);  *p != '\0';  p++ )
  1862. X      {    if( *p == '"' )
  1863. X      continue;
  1864. X    else if( *p != '\\' )
  1865. X      putc(*p, out_fp);
  1866. X    else if( *++p != '\0' )
  1867. X    { putc('\\', out_fp);
  1868. X      putc(*p, out_fp);
  1869. X    }
  1870. X      }
  1871. X      break;
  1872. X    
  1873. X
  1874. X    case ACAT:
  1875. X    
  1876. X      for( link = Down(x);  link != x;  link = NextDown(link) )
  1877. X      {    Child(y, link);
  1878. X    if( type(y) == GAP_OBJ )
  1879. X    { if( vspace(y) > 0 )  putc('\n', out_fp);
  1880. X      else if( hspace(y) > 0 ) putc(' ', out_fp);
  1881. X    }
  1882. X    else if( type(y) == WORD || type(y) == ACAT )  PrintGraphicObject(y);
  1883. X    else if( type(y) != WIDE && !is_index(type(y)) )
  1884. X        /* @Wide, indexes are sometimes inserted by Manifest */
  1885. X    { Error(WARN, &fpos(x), "error in left parameter of %s", KW_GRAPHIC);
  1886. X      debug1(DGP, D, "  type(y) = %s, y =", Image(type(y)));
  1887. X      ifdebug(DGP, D, EchoObject(stderr, y));
  1888. X    }
  1889. X      }
  1890. X      break;
  1891. X
  1892. X
  1893. X    default:
  1894. X    
  1895. X      Error(WARN, &fpos(x), "error in left parameter of %s", KW_GRAPHIC);
  1896. X      debug1(DGP, D, "  type(x) = %s, x =", Image(type(x)));
  1897. X      ifdebug(DGP, D, EchoObject(stderr, x));
  1898. X      break;
  1899. X  }
  1900. X} /* end PrintGraphicObject */
  1901. X
  1902. X
  1903. X/*****************************************************************************/
  1904. X/*                                                                           */
  1905. X/*  DefineGraphicNames(x)                                                    */
  1906. X/*                                                                           */
  1907. X/*  Generate PostScript for xsize, ysize etc. names of graphic object.       */
  1908. X/*                                                                           */
  1909. X/*****************************************************************************/
  1910. X
  1911. XDefineGraphicNames(x)
  1912. XOBJECT x;
  1913. X{ OBJECT y;
  1914. X  assert( type(x) == GRAPHIC, "PrintGraphic: type(x) != GRAPHIC!" );
  1915. X  debug1(DRS, D, "DefineGraphicNames( %s )", EchoObject(null, x));
  1916. X  debug1(DRS, DD, "  style = %s", EchoStyle(&save_style(x)));
  1917. X
  1918. X  fprintf(out_fp, "%d %d %d %d %d %d %d loutgr\n",
  1919. X    size(x, COL), size(x, ROW), back(x, COL), fwd(x, ROW),
  1920. X    font(save_style(x)) <= 0 ? 12*PT : FontSize(font(save_style(x)), x),
  1921. X    width(line_gap(save_style(x))), width(space_gap(save_style(x))));
  1922. X
  1923. X  debug0(DRS, D, "DefineGraphicNames returning.");
  1924. X} /* end DefineGraphicNames */
  1925. X
  1926. X
  1927. X/*****************************************************************************/
  1928. X/*                                                                           */
  1929. X/*  PrintGraphicInclude(x, colmark, rowmark)                                 */
  1930. X/*                                                                           */
  1931. X/*  Print graphic include file, with appropriate surrounds.  This code       */
  1932. X/*  closely follows the PostScript Language Reference Manual, 2n ed.,        */
  1933. X/*  pages 733-5, except we don't clip the included EPSF.                     */
  1934. X/*                                                                           */
  1935. X/*  Note to porters: Version 3.0 of the EPSF standard is not compatible      */
  1936. X/*  with previous versions.  Thus, Lout's output may crash your system.      */
  1937. X/*  If you can find out which comment line(s) are causing the trouble,       */
  1938. X/*  you can add to procedure strip_out to strip them out during the          */
  1939. X/*  file inclusion step.  e.g. on my system %%EOF causes problems, so I      */
  1940. X/*  strip it out.                                                            */
  1941. X/*                                                                           */
  1942. X/*****************************************************************************/
  1943. X#define    SKIPPING    0
  1944. X#define    READING_DNR    1
  1945. X#define FINISHED    2
  1946. X
  1947. Xstatic BOOLEAN strip_out(buff)
  1948. Xunsigned char *buff;
  1949. X{ if( StringBeginsWith(buff, "%%EOF") )  return TRUE;
  1950. X  return FALSE;
  1951. X} /* end strip_out */
  1952. X
  1953. XPrintGraphicInclude(x, colmark, rowmark)
  1954. XOBJECT x; LENGTH colmark, rowmark;
  1955. X{ OBJECT y, full_name;  unsigned char buff[MAX_LINE];
  1956. X  FILE *fp;  int state;
  1957. X  debug0(DRS, D, "PrintGraphicInclude(x)");
  1958. X  assert(type(x)==INCGRAPHIC || type(x)==SINCGRAPHIC, "PrintGraphicInclude!");
  1959. X  assert(sparec(constraint(x)), "PrintGraphicInclude: sparec(constraint(x))!");
  1960. X
  1961. X  /* open the include file and get its full path name */
  1962. X  Child(y, Down(x));
  1963. X  fp = OpenIncGraphicFile(string(y), type(x), &full_name, &fpos(y));
  1964. X  assert( fp != NULL, "PrintGraphicInclude: fp!" );
  1965. X
  1966. X  /* generate appropriate header code */
  1967. X  fprintf(out_fp, "BeginEPSF\n");
  1968. X  CoordTranslate(colmark - back(x, COL), rowmark - fwd(x, ROW));
  1969. X  CoordScale( (float) PT, (float) PT );
  1970. X  CoordTranslate(-back(y, COL), -back(y, ROW));
  1971. X  fprintf(out_fp, "%%%%BeginDocument: %s\n", string(full_name));
  1972. X
  1973. X  /* copy through the include file, except divert resources lines to needs */
  1974. X  /* and strip out some comment lines that cause problems                  */
  1975. X  state = (fgets(buff, MAX_LINE, fp) == NULL) ? FINISHED : SKIPPING;
  1976. X  while( state != FINISHED ) switch(state)
  1977. X  {
  1978. X    case SKIPPING:
  1979. X
  1980. X      if( StringBeginsWith(buff, "%%DocumentNeededResources:") &&
  1981. X      !StringContains(buff, "(atend)") == NULL )
  1982. X      { x = MakeWord(&buff[strlen("%%DocumentNeededResources:")], no_fpos);
  1983. X        Link(needs, x);
  1984. X    state = (fgets(buff, MAX_LINE, fp) == NULL) ? FINISHED : READING_DNR;
  1985. X      }
  1986. X      else
  1987. X      { if( StringBeginsWith(buff, "%%LanguageLevel:") )
  1988. X      Error(WARN, &fpos(x), "ignoring \"%%%%LanguageLevel\" in %s file %s",
  1989. X        KW_INCGRAPHIC, string(full_name));
  1990. X    if( StringBeginsWith(buff, "%%Extensions:") )
  1991. X      Error(WARN, &fpos(x), "ignoring \"%%%%Extensions\" in %s file %s",
  1992. X        KW_INCGRAPHIC, string(full_name));
  1993. X    if( !strip_out(buff) )  fputs(buff, out_fp);
  1994. X    state = (fgets(buff, MAX_LINE, fp) == NULL) ? FINISHED : SKIPPING;
  1995. X      }
  1996. X      break;
  1997. X
  1998. X    case READING_DNR:
  1999. X
  2000. X      if( StringBeginsWith(buff, "%%+") )
  2001. X      {    x = MakeWord(&buff[strlen("%%+")], no_fpos);
  2002. X    Link(needs, x);
  2003. X    state = (fgets(buff, MAX_LINE, fp) == NULL) ? FINISHED : READING_DNR;
  2004. X      }
  2005. X      else
  2006. X      { if( !strip_out(buff) )  fputs(buff, out_fp);
  2007. X    state = (fgets(buff, MAX_LINE, fp) == NULL) ? FINISHED : SKIPPING;
  2008. X      }
  2009. X      break;
  2010. X  }
  2011. X
  2012. X  /* wrapup */
  2013. X  DisposeObject(full_name);
  2014. X  fclose(fp);
  2015. X  fprintf(out_fp, "%%%%EndDocument\nEndEPSF\n");
  2016. X  debug0(DRS, D, "PrintGraphicInclude returning.");
  2017. X} /* end PrintGraphicInclude */
  2018. END_OF_FILE
  2019.   if test 56122 -ne `wc -c <'lout/z24.c'`; then
  2020.     echo shar: \"'lout/z24.c'\" unpacked with wrong size!
  2021.   fi
  2022.   # end of 'lout/z24.c'
  2023. fi
  2024. echo shar: End of archive 3 \(of 30\).
  2025. cp /dev/null ark3isdone
  2026. MISSING=""
  2027. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ; do
  2028.     if test ! -f ark${I}isdone ; then
  2029.     MISSING="${MISSING} ${I}"
  2030.     fi
  2031. done
  2032. if test "${MISSING}" = "" ; then
  2033.     echo You have unpacked all 30 archives.
  2034.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2035. else
  2036.     echo You still must unpack the following archives:
  2037.     echo "        " ${MISSING}
  2038. fi
  2039. exit 0
  2040. exit 0 # Just in case...
  2041.