home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / lout / part09 < prev    next >
Encoding:
Text File  |  1993-06-19  |  81.3 KB  |  2,105 lines

  1. Newsgroups: comp.sources.misc
  2. From: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  3. Subject: v37i107:  lout - Lout document formatting system, v2, Part09/30
  4. Message-ID: <1993Jun1.051815.25628@sparky.imd.sterling.com>
  5. X-Md4-Signature: cc8037361e136d80f39b82ccd6440738
  6. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Tue, 1 Jun 1993 05:18:15 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 107
  13. Archive-name: lout/part09
  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/z14.c lout/z19.c lout/z23.c
  21. # Wrapped by kent@sparky on Sun May 30 19:43:55 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 9 (of 30)."'
  25. if test -f 'lout/z14.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'lout/z14.c'\"
  27. else
  28.   echo shar: Extracting \"'lout/z14.c'\" \(27879 characters\)
  29.   sed "s/^X//" >'lout/z14.c' <<'END_OF_FILE'
  30. X/*@z14.c:Fill Service:FillObject()@*******************************************/
  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:         z14.c                                                      */
  55. X/*  MODULE:       Fill Service                                               */
  56. X/*  EXTERNS:      FillObject()                                               */
  57. X/*                                                                           */
  58. X/*****************************************************************************/
  59. X#include "externs"
  60. X#define TOO_TIGHT_BAD    1048576    /* 2^20; badness of a too tight line         */
  61. X#define TOO_LOOSE_BAD    65536    /* 2^16; the max badness of a too loose line */
  62. X#define    TIGHT_BAD    4096    /* 2^12; the max badness of a tight line     */
  63. X#define    LOOSE_BAD    4096    /* 2^12; the max badness of a loose line     */
  64. X#define    HYPH_BAD    2048    /* 2^11; threshold for calling hyphenation   */
  65. X#define SQRT_TOO_LOOSE    256    /* 2^ 8; sqrt(TOO_LOOSE_BAD)                 */
  66. X#define    SQRT_TIGHT_BAD    64    /* 2^ 6; sqrt(TIGHT_BAD)                     */
  67. X#define    SQRT_LOOSE_BAD    64    /* 2^ 6; sqrt(LOOSE_BAD)                     */
  68. X#define MAX_EXPAND    1
  69. X#define MAX_SHRINK    3
  70. X
  71. X
  72. Xtypedef struct {
  73. X  OBJECT llink;            /* link to gap before left end of interval   */
  74. X  OBJECT rlink;            /* link to gap before right end of interval  */
  75. X  LENGTH nat_width;        /* natural width of interval                 */
  76. X  LENGTH space_width;        /* natural width of spaces in the interval   */
  77. X  int     badness;        /* badness of this interval             */
  78. X  unsigned char   class;    /* badness class of this interval         */
  79. X  unsigned char     tab_count;    /* number of gaps with tab mode in interval  */
  80. X  LENGTH tab_pos;        /* if tab_count > 0, this holds the position */
  81. X                /* of the left edge of the object following  */
  82. X                /* the rightmost tab gap in the interval     */
  83. X  LENGTH width_to_tab;        /* if tab_count > 0, the interval's width up */
  84. X                /* to but not including the rightmost tab    */
  85. X} INTERVAL;
  86. X
  87. X#define unbreakable(g, hyph_allowed)                    \
  88. X(width(g)==0 && (!hyph_allowed || (mode(g)!=HYPH_MODE && mode(g)!=ADD_HYPH)))
  89. X
  90. X
  91. X/*****************************************************************************/
  92. X/*                                                                           */
  93. X/*  Badness classes                                                          */
  94. X/*                                                                           */
  95. X/*****************************************************************************/
  96. X
  97. X#define TOO_LOOSE    0    /* interval is too loose             */
  98. X#define LOOSE        1    /* interval is loose but not too loose         */
  99. X#define TIGHT        2    /* interval is tight but not too tight         */
  100. X#define TOO_TIGHT    3    /* interval is too tight              */
  101. X#define TAB_OVERLAP    4    /* interval has a tab and left part overlaps */
  102. X#define AT_END        5    /* interval ends at right end of paragraph   */
  103. X#define ZERO_AT_LEFT    6    /* interval has a zero-width gap at left     */
  104. X#define ZERO_AT_RIGHT    7    /* interval has a zero-width gap at right    */
  105. X#define EMPTY_INTERVAL    8    /* interval is empty                         */
  106. X
  107. X
  108. X/*@@**************************************************************************/
  109. X/*                                                                           */
  110. X/*  SetIntervalBadness(I)                                                    */
  111. X/*                                                                           */
  112. X/*  Private, calculates the badness and badness class of an interval.        */
  113. X/*  Does not take into account any zero-width gap at either end.             */
  114. X/*                                                                           */
  115. X/*****************************************************************************/
  116. X
  117. X#define SetIntervalBadness(I, max_width, etc_width)            \
  118. X{ OBJECT g; int badness;                        \
  119. X  LENGTH col_width;                            \
  120. X  if( I.llink == x )                            \
  121. X  { col_width = max_width;                        \
  122. X    I.badness = 0;                            \
  123. X  }                                    \
  124. X  else                                    \
  125. X  { col_width = etc_width;                        \
  126. X    Child(g, I.llink);                            \
  127. X    I.badness = save_badness(g);                    \
  128. X  }                                    \
  129. X                                    \
  130. X  if( I.tab_count > 0 && I.width_to_tab > I.tab_pos )            \
  131. X  { I.class = TAB_OVERLAP;                        \
  132. X    I.badness += TOO_TIGHT_BAD;                        \
  133. X  }                                    \
  134. X  else if( MAX_EXPAND*(col_width-I.nat_width) > 2*I.space_width )    \
  135. X  { I.class = I.tab_count > 0 ? LOOSE : TOO_LOOSE;            \
  136. X    badness = (SQRT_TOO_LOOSE*(col_width - I.nat_width)) / col_width;    \
  137. X    I.badness += badness * badness;                    \
  138. X  }                                    \
  139. X  else if( I.nat_width <= col_width )                    \
  140. X  { I.class = LOOSE;                            \
  141. X    badness = (SQRT_LOOSE_BAD*(col_width - I.nat_width)) / col_width;    \
  142. X    I.badness += badness * badness;                    \
  143. X  }                                    \
  144. X  else if( MAX_SHRINK*(I.nat_width-col_width) <= I.space_width )    \
  145. X  { I.class = TIGHT;                            \
  146. X    badness = (SQRT_TIGHT_BAD*(col_width - I.nat_width)) / col_width;    \
  147. X    I.badness += badness * badness;                    \
  148. X  }                                    \
  149. X  else                                    \
  150. X  { I.class = TOO_TIGHT;                        \
  151. X    I.badness += TOO_TIGHT_BAD;                        \
  152. X  }                                    \
  153. X} /* end macro SetIntervalBadness */
  154. X
  155. X/*@@**************************************************************************/
  156. X/*                                                                           */
  157. X/*  CorrectOversizeError(x, link, y, etc_width)                              */
  158. X/*                                                                           */
  159. X/*  Child y of x, whose link is link, has caused an oversize error, either   */
  160. X/*  because it is wider than etc_width, or because it is joined by zero-     */
  161. X/*  width gaps on the left to other objects with oversize total size.        */
  162. X/*  In the first case, the correction is to replace the object by an         */
  163. X/*  empty object; in the second case, the correction is to widen the gap.    */
  164. X/*                                                                           */
  165. X/*****************************************************************************/
  166. X
  167. Xstatic CorrectOversizeError(x, link, y, etc_width, hyph_allowed)
  168. XOBJECT x, link, y;  LENGTH etc_width;  BOOLEAN hyph_allowed;
  169. X{ OBJECT tmp, g;  BOOLEAN done;
  170. X
  171. X  /* if there is a preceding unbreakable gap, make it breakable */
  172. X  done = FALSE;
  173. X  if( PrevDown(link) != x )
  174. X  { Child(g, PrevDown(link));
  175. X    assert( type(g) == GAP_OBJ, "CorrectOversizeError: left gap!" );
  176. X    if( unbreakable(gap(g), hyph_allowed) )
  177. X    { SetGap(gap(g), FALSE, TRUE, FIXED_UNIT, EDGE_MODE, 1);
  178. X      Error(WARN, &fpos(g), "line break may occur here due to wide object");
  179. X      done = TRUE;
  180. X    }
  181. X  }
  182. X
  183. X  /* else replace the wide object by an empty object */
  184. X  if( !done )
  185. X  { Error(WARN, &fpos(y), "%s object deleted (too wide for %s paragraph)",
  186. X        EchoLength(size(y, COL)), EchoLength(etc_width));
  187. X    tmp = MakeWord("", &fpos(x));
  188. X    back(tmp, COL) = fwd(tmp, COL) = 0;
  189. X    back(tmp, ROW) = fwd(tmp, ROW) = 0;
  190. X    word_font(tmp) = 0;
  191. X    Link(link, tmp);
  192. X    DisposeChild(link);
  193. X  }
  194. X
  195. X} /* end CorrectOversizeError */
  196. X
  197. X
  198. X/*@@**************************************************************************/
  199. X/*                                                                           */
  200. X/*  MoveRightToGap(I, x, rlink, right, max_width, etc_width, hyph_word)      */
  201. X/*                                                                           */
  202. X/*  Private.  Shared by IntervalInit and IntervalShiftRightEnd, for moving   */
  203. X/*  to the next gap to the right, setting save_space(newg), checking for     */
  204. X/*  hyphenation case, and setting the interval badness.                      */
  205. X/*                                                                           */
  206. X/*****************************************************************************/
  207. X
  208. X#define MoveRightToGap(I,x,rlink,right,max_width,etc_width,hyph_word)    \
  209. X{ OBJECT newg, foll;                            \
  210. X  BOOLEAN zero_at_right = FALSE;                    \
  211. X                                    \
  212. X  /* search onwards to find newg, the next true breakpoint */        \
  213. X  NextDefiniteWithGap(x, rlink, foll, newg);                \
  214. X                                    \
  215. X  /* set right link and calculate badness of the new interval */    \
  216. X  if( rlink != x )                            \
  217. X  {                                     \
  218. X    /* set save_space(newg) now so that it's OK to forget right */    \
  219. X    if( mode(gap(newg)) == TAB_MODE )                    \
  220. X    { save_space(newg) = ActualGap(0, back(foll,COL), fwd(foll,COL),    \
  221. X      &gap(newg), etc_width, 0) - back(foll, COL);            \
  222. X    }                                    \
  223. X    else                                \
  224. X    { save_space(newg) = ActualGap(fwd(right, COL), back(foll, COL),    \
  225. X      fwd(foll,COL), &gap(newg), etc_width,                \
  226. X      I.nat_width - fwd(right,COL))                    \
  227. X      - back(foll, COL) - fwd(right, COL);                \
  228. X    }                                    \
  229. X                                    \
  230. X    /* if interval ends with hyphen, add hyph_word to nat_width */    \
  231. X    /* NB ADD_HYPH is possible after a restart                  */    \
  232. X    if( hyph_allowed &&                            \
  233. X    (mode(gap(newg)) == HYPH_MODE || mode(gap(newg)) == ADD_HYPH) )    \
  234. X    { if( type(right) == WORD &&                     \
  235. X        !(string(right)[strlen(string(right))-1] == '-' ||    \
  236. X        (string(right)[strlen(string(right))-1] == '"' &&    \
  237. X         string(right)[strlen(string(right))-2] == '-' )) )    \
  238. X      {                                    \
  239. X    /* make sure hyph_word exists and is of the right font */    \
  240. X    if( hyph_word == nil )                        \
  241. X    { hyph_word = MakeWord("-", &fpos(x));                \
  242. X      word_font(hyph_word) = 0;                    \
  243. X    }                                \
  244. X    if( word_font(hyph_word) != font(save_style(x)) )        \
  245. X    { word_font(hyph_word) = font(save_style(x));            \
  246. X      FposCopy(fpos(hyph_word), fpos(x));                \
  247. X      FontAtomSize(hyph_word);                    \
  248. X    }                                \
  249. X                                    \
  250. X    mode(gap(newg)) = ADD_HYPH;                    \
  251. X    I.nat_width += size(hyph_word, COL);                \
  252. X    debug0(DOF, DD, "   adding hyph_word from nat_width\n");    \
  253. X      }                                    \
  254. X    }                                    \
  255. X    else if( unbreakable(gap(newg), hyph_allowed) ) zero_at_right=TRUE;    \
  256. X                                    \
  257. X    I.rlink = Up(newg);                            \
  258. X  }                                    \
  259. X  else I.rlink = x;                            \
  260. X  SetIntervalBadness(I, max_width, etc_width);                \
  261. X  if( zero_at_right )  I.class = ZERO_AT_RIGHT;                \
  262. X}
  263. X
  264. X/*@@**************************************************************************/
  265. X/*                                                                           */
  266. X/*  IntervalInit(I, x, max_width, etc_width, hyph_word)                      */
  267. X/*                                                                           */
  268. X/*  Set I to the first interval of x.                                        */
  269. X/*                                                                           */
  270. X/*****************************************************************************/
  271. X
  272. X#define IntervalInit(I, x, max_width, etc_width, hyph_word)        \
  273. X{ OBJECT rlink, right, newg, foll;                    \
  274. X  I.llink = x;                                \
  275. X                                    \
  276. X  FirstDefinite(x, rlink, right);                    \
  277. X  if( rlink == x )  I.class = AT_END, I.rlink = x;            \
  278. X  else                                    \
  279. X  {                                     \
  280. X    /* have first definite object, so set interval width etc. */    \
  281. X    I.nat_width = size(right, COL);                    \
  282. X    I.space_width = 0;                            \
  283. X    I.tab_count = 0;                            \
  284. X                                    \
  285. X    /* move to gap, check hyphenation there etc. */            \
  286. X    MoveRightToGap(I,x,rlink,right,max_width,etc_width,hyph_word);     \
  287. X  }                                    \
  288. X} /* end macro IntervalInit */
  289. X
  290. X
  291. X/*****************************************************************************/
  292. X/*                                                                           */
  293. X/*  IntervalShiftRightEnd(I, x, hyph_word, max_width, etc_width)             */
  294. X/*                                                                           */
  295. X/*  Shift the right end of interval I one place to the right.                */
  296. X/*                                                                           */
  297. X/*****************************************************************************/
  298. X
  299. X#define IntervalShiftRightEnd(I, x, hyph_word, max_width, etc_width)     \
  300. X{ OBJECT rlink, g, right;                        \
  301. X  assert( I.class != AT_END, "IntervalShiftRightEnd: AT_END!" );    \
  302. X  rlink = I.rlink;                            \
  303. X  if( rlink == x ) I.class = AT_END;                    \
  304. X  else                                    \
  305. X  {                                    \
  306. X    /* I is optimal here so save its badness and left endpoint */    \
  307. X    Child(g, rlink);                            \
  308. X    assert( type(g) == GAP_OBJ, "IntervalShiftRightEnd: type(g)!" );    \
  309. X    save_badness(g) = I.badness;                    \
  310. X    save_prev(g) = I.llink;                        \
  311. X                                    \
  312. X    /* if hyphenation case, must take away width of hyph_word */    \
  313. X    if( mode(gap(g)) == ADD_HYPH )                    \
  314. X    { I.nat_width -= size(hyph_word,COL);                \
  315. X      debug0(DOF, DD, "   subtracting hyph_word from nat_width");    \
  316. X    }                                    \
  317. X                                    \
  318. X    /* find definite object which must lie just to the right of g */    \
  319. X    NextDefinite(x, rlink, right);                    \
  320. X    assert( rlink != x, "IntervalShiftRightEnd: rlink == x!" );        \
  321. X                                    \
  322. X    /* modify I to reflect the addition of g and right */        \
  323. X    if( mode(gap(g)) == TAB_MODE )                    \
  324. X    { I.tab_count++;                            \
  325. X      I.tab_pos = save_space(g);                    \
  326. X      I.width_to_tab = I.nat_width;                    \
  327. X      I.nat_width = save_space(g) + size(right, COL);            \
  328. X      I.space_width = 0;                        \
  329. X    }                                    \
  330. X    else                                \
  331. X    { I.nat_width += save_space(g) + size(right, COL);            \
  332. X      I.space_width += save_space(g);                    \
  333. X    }                                    \
  334. X                                    \
  335. X    /* now shift one step to the right */                \
  336. X    MoveRightToGap(I, x, rlink, right, max_width, etc_width,hyph_word);    \
  337. X  }                                    \
  338. X} /* end macro IntervalShiftRightEnd */
  339. X
  340. X/*@@**************************************************************************/
  341. X/*                                                                           */
  342. X/*  IntervalShiftLeftEnd(I, x, max_width, etc_width)                         */
  343. X/*                                                                           */
  344. X/*  Shift the left end of interval I one place to the right.                 */
  345. X/*                                                                           */
  346. X/*****************************************************************************/
  347. X
  348. X#define IntervalShiftLeftEnd(I, x, max_width, etc_width)        \
  349. X{ OBJECT llink, left, lgap, y;                        \
  350. X  debug1(DOF, DDD, "IntervalShiftLeftEnd(%s)", IntervalPrint(I, x));    \
  351. X  assert( I.class != AT_END, "IntervalShiftLeftEnd: AT_END!" );        \
  352. X                                    \
  353. X  /* find left, the leftmost definite object of I */            \
  354. X  llink = I.llink;                            \
  355. X  NextDefinite(x, llink, left);                        \
  356. X  assert( llink != x, "IntervalShiftLeftEnd: llink == x!" );        \
  357. X                                    \
  358. X  /* find lgap, the first true breakpoint following left */        \
  359. X  NextDefiniteWithGap(x, llink, y, lgap);                \
  360. X  assert( llink != x, "IntervalShiftLeftEnd: llink == x!" );        \
  361. X                                    \
  362. X  /* calculate width and badness of interval minus left and lgap */    \
  363. X  if( mode(gap(lgap)) == TAB_MODE )                    \
  364. X  { assert( I.tab_count > 0 || Up(lgap) == I.rlink,            \
  365. X            "IntervalShiftLeftEnd: tab_count <= 0!" );    \
  366. X    I.tab_count--;                            \
  367. X    if( I.tab_count == 0 )  I.nat_width -= save_space(lgap);        \
  368. X  }                                    \
  369. X  else /* take from nat_width, or if tab, from width_to_tab */        \
  370. X  { if( I.tab_count == 0 )                        \
  371. X    { I.nat_width -= save_space(lgap) + size(left, COL);        \
  372. X      I.space_width -= save_space(lgap);                \
  373. X    }                                    \
  374. X    else if( I.tab_count == 1 )                        \
  375. X    { I.width_to_tab -= save_space(lgap) + size(left, COL);        \
  376. X    }                                    \
  377. X    /* else no changes since tabs hide them */                \
  378. X  }                                    \
  379. X  I.llink = Up(lgap);                            \
  380. X  if( I.llink == I.rlink )  I.class = EMPTY_INTERVAL;            \
  381. X  else                                    \
  382. X  { SetIntervalBadness(I, max_width, etc_width);            \
  383. X    if( unbreakable(gap(lgap), hyph_allowed) )  I.class = ZERO_AT_LEFT;    \
  384. X  }                                    \
  385. X  debug1(DOF, DDD, "IShiftLeftEnd returning %s", IntervalPrint(I, x));    \
  386. X} /* end macro IntervalShiftLeftEnd */
  387. X
  388. X
  389. X/*****************************************************************************/
  390. X/*                                                                           */
  391. X/*  IntervalBadness(I)                                                       */
  392. X/*                                                                           */
  393. X/*  Return the badness of interval I.                                        */
  394. X/*                                                                           */
  395. X/*****************************************************************************/
  396. X
  397. X#define IntervalBadness(I)    (I.badness)
  398. X
  399. X
  400. X/*@@**************************************************************************/
  401. X/*                                                                           */
  402. X/*  IntervalClass(I)                                                         */
  403. X/*                                                                           */
  404. X/*  Return the badness class of interval I.                                  */
  405. X/*                                                                           */
  406. X/*****************************************************************************/
  407. X
  408. X#define IntervalClass(I)    (I.class)
  409. X
  410. X
  411. X#if DEBUG_ON
  412. X/*****************************************************************************/
  413. X/*                                                                           */
  414. X/*  IntervalPrint(I, x)                                                      */
  415. X/*                                                                           */
  416. X/*  Return string image of the contents of interval I of ACAT x.             */
  417. X/*                                                                           */
  418. X/*****************************************************************************/
  419. X
  420. Xunsigned char *IntervalPrint(I, x)
  421. XINTERVAL I;  OBJECT x;
  422. X{ static char *class_name[] =
  423. X    { "TOO_LOOSE", "LOOSE", "TIGHT", "TOO_TIGHT", "TAB_OVERLAP", "AT_END",
  424. X      "ZERO_AT_LEFT", "ZERO_AT_RIGHT" };
  425. X  unsigned char buff[100]; static unsigned char res[300];
  426. X  OBJECT link, y, g, prev, z; int i;
  427. X  if( I.llink == I.rlink )  return (unsigned char *) "[]";
  428. X  strcpy(res, "[");
  429. X  g = nil;
  430. X  for( link = NextDown(I.llink);  link != I.rlink;  link = NextDown(link) )
  431. X  { assert(link != x, "IntervalPrint: link == x!");
  432. X    Child(y, link);
  433. X    assert(y != x, "IntervalPrint: y == x!");
  434. X    if( type(y) == GAP_OBJ )
  435. X    { g = y;
  436. X      if( Down(g) != g )
  437. X      {    Child(z, Down(g));
  438. X    sprintf(buff, " %s%s ", EchoCatOp(ACAT, mark(gap(g)), join(gap(g))),
  439. X         type(z) == WORD ? string(z) : Image(type(z)));
  440. X      }
  441. X      else sprintf(buff, "%*s", hspace(g) + vspace(g), "");
  442. X      strcat(res, buff);
  443. X    }
  444. X    else strcat(res, type(y) == WORD ? string(y) : Image(type(y)));
  445. X  }
  446. X  sprintf(buff, "] n%s, s%s (%s %d)", EchoLength(I.nat_width),
  447. X    EchoLength(I.space_width), class_name[I.class], I.badness);
  448. X  strcat(res, buff);
  449. X  if( I.tab_count > 0 )
  450. X  { sprintf(buff, " <%d %s:%s>", I.tab_count,
  451. X    EchoLength(I.width_to_tab), EchoLength(I.tab_pos));
  452. X    strcat(res, buff);
  453. X  }
  454. X  return res;
  455. X} /* end IntervalPrint */
  456. X#endif
  457. X
  458. X
  459. X/*@@**************************************************************************/
  460. X/*                                                                           */
  461. X/*  FillObject(x, c)                                                         */
  462. X/*                                                                           */
  463. X/*  Break ACAT x into lines using optimal breakpoints.                       */
  464. X/*                                                                           */
  465. X/*****************************************************************************/
  466. X
  467. XOBJECT FillObject(x, c)
  468. XOBJECT x;  CONSTRAINT *c;
  469. X{ INTERVAL I, BestI;  OBJECT res, gp, tmp, z, y, link, prev;
  470. X  LENGTH max_width, etc_width, outdent_margin, f;
  471. X  static OBJECT hyph_word = nil;
  472. X  BOOLEAN can_hyphenate;    /* TRUE when it is possible to call Hyphenate() */
  473. X  BOOLEAN hyph_allowed;        /* TRUE when hyphenation of words is permitted  */
  474. X
  475. X  assert( type(x) == ACAT, "FillObject: type(x) != ACAT!" );
  476. X
  477. X  /* set max_width (width of 1st line) and etc_width (width of later lines) */
  478. X  max_width = min(fc(*c), bfc(*c));
  479. X  if( display_style(save_style(x)) == DISPLAY_OUTDENT )
  480. X  { outdent_margin = 2 * FontSize(font(save_style(x)), x);
  481. X    etc_width = max_width - outdent_margin;
  482. X  }
  483. X  else etc_width = max_width;
  484. X  assert( size(x, COL) > max_width, "FillObject: initial size!" );
  485. X
  486. X  /* add &1rt {} to end of paragraph */
  487. X  gp = New(GAP_OBJ);
  488. X  hspace(gp) = 1;  vspace(gp) = 0;
  489. X  SetGap(gap(gp), FALSE, TRUE, AVAIL_UNIT, TAB_MODE, 1*FR);
  490. X  tmp = MakeWord("1rt", &fpos(x));
  491. X  Link(gp, tmp);
  492. X  Link(x, gp);
  493. X  tmp = MakeWord("", &fpos(x));
  494. X  back(tmp, COL) = fwd(tmp, COL) = 0;
  495. X  back(tmp, ROW) = fwd(tmp, ROW) = 0;
  496. X  word_font(tmp) = 0;
  497. X  Link(x, tmp);
  498. X  debug2(DOF, D, "FillObject(x, %s); %s",
  499. X    EchoConstraint(c), EchoStyle(&save_style(x)));
  500. X  ifdebug(DOF, DD, EchoObject(stderr, x); fprintf(stderr, "\n\n") );
  501. X
  502. X  /* initially we can hyphenate if hyphenation is on, but not first pass */
  503. X  if( hyph_style(save_style(x)) == HYPH_UNDEF )
  504. X    Error(FATAL, &fpos(x), "hyphen or nohyphen option missing");
  505. X  can_hyphenate = (hyph_style(save_style(x)) == HYPH_ON);
  506. X  hyph_allowed = FALSE;
  507. X
  508. X  /* initialize I to first interval, BestI to best ending here, and run */
  509. X  RESTART:
  510. X  IntervalInit(I, x, max_width, etc_width, hyph_word);
  511. X  BestI = I;
  512. X  while( IntervalClass(I) != AT_END )
  513. X  {
  514. X    debug1(DOF, D, "loop:  %s", IntervalPrint(I, x));
  515. X    switch( IntervalClass(I) )
  516. X    {
  517. X
  518. X      case TOO_LOOSE:
  519. X      
  520. X    /* too loose, so save best and shift right end */
  521. X    if( IntervalBadness(BestI) < IntervalBadness(I) )  I = BestI;
  522. X    debug1(DOF, D, "BestI: %s\n", IntervalPrint(I, x));
  523. X    /* NB no break */
  524. X
  525. X
  526. X      case ZERO_AT_RIGHT:
  527. X
  528. X    IntervalShiftRightEnd(I, x, hyph_word, max_width, etc_width);
  529. X    BestI = I;
  530. X    break;
  531. X
  532. X
  533. X      case LOOSE:
  534. X      case TIGHT:
  535. X      
  536. X    /* reasonable, so check best and shift left end */
  537. X    if( IntervalBadness(I) < IntervalBadness(BestI) )  BestI = I;
  538. X    /* NB no break */
  539. X
  540. X
  541. X      case ZERO_AT_LEFT:
  542. X      case TAB_OVERLAP:
  543. X      case TOO_TIGHT:
  544. X      
  545. X    /* too tight, or zero-width gap at left end, so shift left end */
  546. X    IntervalShiftLeftEnd(I, x, max_width, etc_width);
  547. X    break;
  548. X
  549. X
  550. X      case EMPTY_INTERVAL:
  551. X
  552. X    PrevDefinite(x, I.llink, y);
  553. X    if( can_hyphenate )
  554. X    { x = Hyphenate(x);
  555. X      can_hyphenate = FALSE;
  556. X      hyph_allowed = TRUE;
  557. X    }
  558. X    else
  559. X      CorrectOversizeError(x, I.llink, y, etc_width, hyph_allowed);
  560. X    goto RESTART;
  561. X    break;
  562. X
  563. X
  564. X      default:
  565. X      
  566. X    Error(INTERN, &fpos(x), "FillObject: unknown interval class!");
  567. X    break;
  568. X
  569. X    }
  570. X  }
  571. X
  572. X  /* do end processing */
  573. X  ifdebug(DOF, D,
  574. X    debug0(DOF, D, "final result:");
  575. X    debug1(DOF, D, "%s", IntervalPrint(BestI, x));
  576. X    while( BestI.llink != x )
  577. X    { BestI.rlink = BestI.llink;
  578. X      Child(gp, BestI.rlink);
  579. X      BestI.llink = save_prev(gp);
  580. X      debug1(DOF, D, "%s", IntervalPrint(BestI, x));
  581. X    }
  582. X  );
  583. X
  584. X  if( I.llink == x )
  585. X  { /* since line did not fit initally, this must mean either that a large  */
  586. X    /* word was discarded, or else that the line was only slightly tight    */
  587. X    res = x;
  588. X    back(res, COL) = 0;
  589. X    fwd(res, COL) = max_width;
  590. X  }
  591. X  else if( can_hyphenate && IntervalBadness(BestI) > HYPH_BAD )
  592. X  { x = Hyphenate(x);
  593. X    can_hyphenate = FALSE;
  594. X    hyph_allowed = TRUE;
  595. X    goto RESTART;
  596. X  }
  597. X  else
  598. X  { OBJECT lgap, llink;
  599. X    res = New(VCAT);
  600. X    back(res, COL) = 0;
  601. X    fwd(res, COL) = max_width;
  602. X    ReplaceNode(res, x);
  603. X    llink = I.llink;
  604. X
  605. X    /* break the lines of x */
  606. X    while( llink != x )
  607. X    { y = New(ACAT);
  608. X      FposCopy(fpos(y), fpos(x));
  609. X      StyleCopy(save_style(y), save_style(x));
  610. X      if( Down(res) != res &&
  611. X        (display_style(save_style(y)) == DISPLAY_ADJUST ||
  612. X         display_style(save_style(y)) == DISPLAY_OUTDENT) )
  613. X     display_style(save_style(y)) = DO_ADJUST;
  614. X      back(y, COL) = 0;
  615. X      fwd(y, COL) = max_width;
  616. X
  617. X      /* if outdented paragraphs, add 2.0f @Wide & to front of new line */
  618. X      if( display_style(save_style(x)) == DISPLAY_OUTDENT )
  619. X      {
  620. X    OBJECT t1, t2, z;
  621. X    t1 = MakeWord("", &fpos(x));
  622. X    back(t1, COL) = fwd(t1, COL) = 0;
  623. X    back(t1, ROW) = fwd(t1, ROW) = 0;
  624. X    word_font(t1) = 0;
  625. X    t2 = New(WIDE);
  626. X    SetConstraint(constraint(t2), MAX_LEN, outdent_margin, MAX_LEN);
  627. X    back(t2, COL) = 0;  fwd(t2, COL) = outdent_margin;
  628. X    Link(t2, t1);
  629. X    Link(y, t2);
  630. X    z = New(GAP_OBJ);
  631. X    hspace(z) = vspace(z) = 0;
  632. X    SetGap(gap(z), FALSE, TRUE, FIXED_UNIT, EDGE_MODE, 0);
  633. X    Link(y, z);
  634. X      }
  635. X
  636. X      /* move the line to below y */
  637. X      TransferLinks(NextDown(llink), x, y);
  638. X
  639. X      /* add hyphen to end of previous line, if lgap is ADD_HYPH */
  640. X      Child(lgap, llink);
  641. X      if( mode(gap(lgap)) == ADD_HYPH )
  642. X      {
  643. X    OBJECT z = New(GAP_OBJ);
  644. X    debug0(DOF, DD, "   adding hyphen\n");
  645. X    hspace(z) = vspace(z) = 0;
  646. X    SetGap(gap(z), FALSE, TRUE, FIXED_UNIT, EDGE_MODE, 0);
  647. X    Link(x, z);
  648. X    z = MakeWord("-", &fpos(y));
  649. X    word_font(z) = font(save_style(x));
  650. X    FontAtomSize(z);
  651. X    Link(x, z);
  652. X      }
  653. X
  654. X      /* attach y to res, recycle lgap for gap separating the two lines */
  655. X      Link(NextDown(res), y);
  656. X      MoveLink(llink, NextDown(res), PARENT);
  657. X      hspace(lgap) = 0;
  658. X      vspace(lgap) = 1;
  659. X      GapCopy(gap(lgap), line_gap(save_style(x)));
  660. X
  661. X      /* move on to previous line */
  662. X      llink = save_prev(lgap);
  663. X    }
  664. X
  665. X    /* attach first line, x, to res */
  666. X    Link(NextDown(res), x);
  667. X    back(x, COL) = 0;
  668. X    fwd(x, COL) = max_width;
  669. X    if( display_style(save_style(x)) == DISPLAY_ADJUST ||
  670. X    display_style(save_style(x)) == DISPLAY_OUTDENT )
  671. X      display_style(save_style(x)) = DO_ADJUST;
  672. X
  673. X    /* delete the final &1rt {} from the last line, to help clines */
  674. X    Child(y, LastDown(res));
  675. X    assert( Down(y) != LastDown(y), "FillObject: empty last line!" );
  676. X    Child(z, LastDown(y));
  677. X    assert( type(z)==WORD && string(z)[0] == '\0', "FillObject: last word!" );
  678. X    DisposeChild(LastDown(y));
  679. X    Child(z, LastDown(y));
  680. X    assert( type(z) == GAP_OBJ, "FillObject: last gap_obj!" );
  681. X    DisposeChild(LastDown(y));
  682. X
  683. X    /* recalculate the width of the last line, since it's smaller */
  684. X    FirstDefinite(y, link, z);
  685. X    assert( link != y, "FillObject: last line is empty!" );
  686. X    f = back(z, COL);  prev = z;
  687. X    NextDefiniteWithGap(y, link, z, gp);
  688. X    while( link != y )
  689. X    {
  690. X      f += MinGap(fwd(prev, COL), back(y, COL), fwd(y, COL), &gap(gp));
  691. X      prev = z;
  692. X      NextDefiniteWithGap(y, link, z, gp);
  693. X    }
  694. X    fwd(y, COL) = f + fwd(prev, COL);
  695. X
  696. X    /* make last line DO_ADJUST if it's oversize */
  697. X    if( size(y, COL) > max_width )  display_style(save_style(y)) = DO_ADJUST;
  698. X  }
  699. X
  700. X  debug0(DOF, D, "FillObject exiting");
  701. X  return res;
  702. X} /* end FillObject */
  703. END_OF_FILE
  704.   if test 27879 -ne `wc -c <'lout/z14.c'`; then
  705.     echo shar: \"'lout/z14.c'\" unpacked with wrong size!
  706.   fi
  707.   # end of 'lout/z14.c'
  708. fi
  709. if test -f 'lout/z19.c' -a "${1}" != "-c" ; then 
  710.   echo shar: Will not clobber existing file \"'lout/z19.c'\"
  711. else
  712.   echo shar: Extracting \"'lout/z19.c'\" \(22219 characters\)
  713.   sed "s/^X//" >'lout/z19.c' <<'END_OF_FILE'
  714. X/*@z19.c:Galley Attaching:AttachGalley(), DetachGalley()@*********************/
  715. X/*                                                                           */
  716. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  717. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  718. X/*                                                                           */
  719. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  720. X/*  Basser Department of Computer Science                                    */
  721. X/*  The University of Sydney 2006                                            */
  722. X/*  AUSTRALIA                                                                */
  723. X/*                                                                           */
  724. X/*  This program is free software; you can redistribute it and/or modify     */
  725. X/*  it under the terms of the GNU General Public License as published by     */
  726. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  727. X/*  any later version.                                                       */
  728. X/*                                                                           */
  729. X/*  This program is distributed in the hope that it will be useful,          */
  730. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  731. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  732. X/*  GNU General Public License for more details.                             */
  733. X/*                                                                           */
  734. X/*  You should have received a copy of the GNU General Public License        */
  735. X/*  along with this program; if not, write to the Free Software              */
  736. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  737. X/*                                                                           */
  738. X/*  FILE:         z19.c                                                      */
  739. X/*  MODULE:       Galley Attaching                                           */
  740. X/*  EXTERNS:      AttachGalley(), DetachGalley()                             */
  741. X/*                                                                           */
  742. X/*****************************************************************************/
  743. X#include "externs"
  744. X
  745. X
  746. X/*****************************************************************************/
  747. X/*                                                                           */
  748. X/*  OBJECT SearchGalley(start, sym, forwards, subgalleys, closures, input)   */
  749. X/*                                                                           */
  750. X/*  Search a galley and its sub-galleys for a target which uses sym.  The    */
  751. X/*  meanings of the flags are as follows:                                    */
  752. X/*                                                                           */
  753. X/*    forwards     If TRUE, search forwards from just after start, else      */
  754. X/*                 search backwards from just before start                   */
  755. X/*    subgalleys   If TRUE, search down into sub-galleys of this galley      */
  756. X/*    closures     If TRUE, closures in this galley are acceptable results   */
  757. X/*    input        If TRUE, InputSym is an acceptable result                 */
  758. X/*                                                                           */
  759. X/*****************************************************************************/
  760. X
  761. XOBJECT SearchGalley(start, sym, forwards, subgalleys, closures, input)
  762. XOBJECT start, sym;  BOOLEAN forwards, subgalleys, closures, input;
  763. X{ OBJECT y, res, z, zlink, link;
  764. X  debug5(DGA, D, "[SearchGalley( start, %s, %s, %s, %s, %s )", SymName(sym),
  765. X    forwards ? "fwd" : "back", subgalleys ? "subgalleys" : "nosubgalleys",
  766. X    closures ? "closures" : "noclosures", input ? "input" : "noinput");
  767. X  assert( type(start) == LINK || type(start) == HEAD, "SearchGalley: start!" );
  768. X
  769. X  link = forwards ? NextDown(start) : PrevDown(start);
  770. X  res = nil;
  771. X  while( res == nil && type(link) != HEAD )
  772. X  { Child(y, link);
  773. X    debug1(DGA, DD, "  examining %s", EchoObject(null, y));
  774. X    switch( type(y) )
  775. X    {
  776. X      case UNATTACHED:
  777. X      case RECEIVING:
  778. X    
  779. X    if( subgalleys )
  780. X    for( zlink = Down(y); zlink!=y && res==nil;  zlink = NextDown(zlink) )
  781. X    { Child(z, zlink);
  782. X      res = SearchGalley(z, sym, TRUE, TRUE, TRUE, input);
  783. X    }
  784. X    if( !res && input && type(y)==RECEIVING && actual(actual(y))==InputSym )
  785. X      res = y;
  786. X    break;
  787. X
  788. X
  789. X      case RECEPTIVE:
  790. X    
  791. X    if( closures && type(actual(y)) == CLOSURE
  792. X             && SearchUses(actual(actual(y)), sym) )  res = y;
  793. X    else if( input && actual(actual(y)) == InputSym )  res = y;
  794. X    break;
  795. X
  796. X
  797. X      default:
  798. X    
  799. X    break;
  800. X
  801. X    }
  802. X    link = forwards ? NextDown(link) : PrevDown(link);
  803. X  }
  804. X  debug1(DGA, D, "]SearchGalley returning %s", EchoObject(null, res));
  805. X  return res;
  806. X} /* end SearchGalley */
  807. X
  808. X
  809. X/*@@**************************************************************************/
  810. X/*                                                                           */
  811. X/*  AttachGalley(hd, inners)                                                 */
  812. X/*                                                                           */
  813. X/*  Attach galley hd, which may be unsized, to a destination.  This involves */
  814. X/*  searching for a destination forward or back from hd's attachment point,  */
  815. X/*  and promoting up to and including the first definite component of hd.    */
  816. X/*                                                                           */
  817. X/*  Although AttachGalley never flushes any galleys, it may identify some    */
  818. X/*  galleys which should be flushed, even if the attach is itself not        */
  819. X/*  successful.  These are returned in *inners, or nil if none.              */
  820. X/*                                                                           */
  821. X/*****************************************************************************/
  822. X
  823. XAttachGalley(hd, inners)
  824. XOBJECT hd, *inners;
  825. X{ OBJECT index;            /* the index of hd in the enclosing galley   */
  826. X  OBJECT hd_inners;        /* inner galleys of hd, if unsized           */
  827. X  OBJECT dest;            /* the target @Galley hd empties into        */
  828. X  OBJECT dest_index;        /* the index of dest                         */
  829. X  OBJECT target;        /* the target indefinite containing dest     */
  830. X  OBJECT target_index;        /* the index of target                       */
  831. X  OBJECT target_galley;        /* the body of target, made into a galley    */
  832. X  OBJECT tg_inners;        /* inner galleys of target_galley            */
  833. X  BOOLEAN need_precedes;    /* true if destination lies before galley    */
  834. X  OBJECT recs;            /* list of recursive definite objects        */
  835. X  OBJECT link, y;        /* for scanning through the components of hd */
  836. X  CONSTRAINT c;            /* temporary variable holding a constraint   */
  837. X  OBJECT env, n1, tmp, zlink, z, sym;    /* placeholders and temporaries         */
  838. X  BOOLEAN was_sized;        /* true if sized(hd) initially               */
  839. X
  840. X  debug2(DGA, D, "[AttachGalley(Galley %s into %s)",
  841. X    SymName(actual(hd)), SymName(whereto(hd)));
  842. X  ifdebug(DGA, DD, EchoObject(stderr, hd));
  843. X  assert( Up(hd) != hd, "AttachGalley: no index!" );
  844. X  Parent(index, Up(hd));
  845. X  assert( type(index) == UNATTACHED, "AttachGalley: not UNATTACHED!" );
  846. X  *inners = hd_inners = tg_inners = nil;
  847. X  was_sized = sized(hd);
  848. X
  849. X  for(;;)
  850. X  {
  851. X    /*************************************************************************/
  852. X    /*                                                                       */
  853. X    /*  Search for a destination for hd.  If hd is unsized, search for       */
  854. X    /*  inner galleys preceding it first of all, then for receptive objects  */
  855. X    /*  following it, possibly in inner galleys.  If no luck, exit.          */
  856. X    /*  If hd is sized, search only for receptive objects in the current     */
  857. X    /*  galley below the current spot, and fail if can't find any.           */
  858. X    /*                                                                       */
  859. X    /*************************************************************************/
  860. X
  861. X    sym = whereto(hd);
  862. X    if( sized(hd) )
  863. X    {
  864. X      /* sized galley case: search on from current spot */
  865. X      target_index = SearchGalley(Up(index), sym, TRUE, FALSE, TRUE, TRUE);
  866. X      if( target_index == nil )
  867. X      {    
  868. X    /* search failed to find any new target, so kill the galley */
  869. X    for( link = Down(hd); link != hd; link = NextDown(link) )
  870. X    { Child(y, link);
  871. X      if( type(y) == SPLIT )  Child(y, DownDim(y, ROW));
  872. X      if( is_definite(type(y)) )  break;
  873. X    }
  874. X    if( link != hd )
  875. X        Error(WARN, &fpos(y), "galley %s deleted from here: no target",
  876. X        SymName(actual(hd)));
  877. X    debug0(DGA, D, "calling KillGalley from AttachGalley (a)");
  878. X    KillGalley(hd);
  879. X    debug0(DGA, D, "]AttachGalley returning: no target for sized galley");
  880. X    return;
  881. X      }
  882. X      else if( actual(actual(target_index)) == InputSym )
  883. X      {
  884. X    /* search found input object, so suspend on that */
  885. X    DeleteNode(index);
  886. X    Link(target_index, hd);
  887. X    debug0(DGA, D, "]AttachGalley returning: InputSym");
  888. X    return;
  889. X      }
  890. X
  891. X    }
  892. X    else /* unsized galley, either backwards or normal */
  893. X    {
  894. X      if( backward(hd) )
  895. X      {    target_index= SearchGalley(Up(index), sym, FALSE, TRUE, TRUE, FALSE);
  896. X    need_precedes = FALSE;
  897. X      }
  898. X      else
  899. X      {    target_index = SearchGalley(Up(index), sym, FALSE, TRUE, FALSE, FALSE);
  900. X    need_precedes = (target_index != nil);
  901. X    if( target_index == nil )
  902. X      target_index = SearchGalley(Up(index), sym, TRUE, TRUE, TRUE, FALSE);
  903. X      }
  904. X
  905. X      /* if no luck, exit without error */
  906. X      if( target_index == nil )
  907. X      {    debug0(DGA, D, "]AttachGalley returning: no target for unsized galley");
  908. X    return;
  909. X      }
  910. X    }
  911. X    assert( type(target_index) == RECEPTIVE, "AttachGalley: target_index!" );
  912. X    target = actual(target_index);
  913. X    assert( type(target) == CLOSURE, "AttachGalley: target!" );
  914. X
  915. X    /* set target_galley to the expanded value of target */
  916. X    EnterErrorBlock(FALSE);
  917. X    target_galley = New(HEAD);
  918. X    FposCopy(fpos(target_galley), fpos(target));
  919. X    actual(target_galley) = actual(target);
  920. X    whereto(target_galley) = ready_galls(target_galley) = nil;
  921. X    backward(target_galley) = must_expand(target_galley) = FALSE;
  922. X    sized(target_galley) = FALSE;
  923. X    Constrained(target, &c, COL);
  924. X    if( !constrained(c) )  Error(FATAL, &fpos(target),
  925. X       "receptive symbol %s has unconstrained width", SymName(actual(target)));
  926. X    debug2(DSC, D, "Constrained( %s, COL ) = %s",
  927. X    EchoObject(null, target), EchoConstraint(&c));
  928. X    debug1(DGA, DD, "  expanding %s", EchoObject(null, target));
  929. X    tmp = CopyObject(target, no_fpos);
  930. X    Link(target_galley, tmp);
  931. X    if( !FitsConstraint(0, 0, c) )
  932. X    { debug0(DGA, D, "  reject: target_galley horizontal constraint is -1");
  933. X      goto REJECT;
  934. X    }
  935. X    env = DetachEnv(tmp);
  936. X    SizeGalley(target_galley, env, external(target), threaded(target),
  937. X    non_blocking(target_index), trigger_externs(target_index),
  938. X    &save_style(target), &c, whereto(hd), &dest_index, &recs, &tg_inners);
  939. X    if( recs != nil )  ExpandRecursives(recs);
  940. X    dest = actual(dest_index);
  941. X
  942. X    /* verify that hd satisfies any horizontal constraint on dest */
  943. X    debug1(DGA, DD, "  checking COL fit of hd in %s", SymName(actual(dest)));
  944. X    Constrained(dest, &c, COL);
  945. X    debug2(DSC, D, "Constrained( %s, COL ) = %s",
  946. X    EchoObject(null, dest), EchoConstraint(&c));
  947. X    assert( constrained(c), "AttachGalley: dest unconstrained!" );
  948. X    if( !sized(hd) )
  949. X    { EnterErrorBlock(TRUE);
  950. X      if( !FitsConstraint(0, 0, c) )
  951. X      {    debug0(DGA, D, "  reject: hd horizontal constraint is -1");
  952. X    goto REJECT;
  953. X      }
  954. X      n1 = nil;
  955. X      Child(y, Down(hd));
  956. X      env = DetachEnv(y);
  957. X      /*** to set non_blocking() to FALSE seems doubtful!
  958. X      SizeGalley(hd, env, TRUE, threaded(dest), FALSE, TRUE,
  959. X        &save_style(dest), &c, nil, &n1, &recs, &hd_inners);
  960. X      *** */
  961. X      SizeGalley(hd, env, TRUE, threaded(dest), non_blocking(target_index),
  962. X    TRUE, &save_style(dest), &c, nil, &n1, &recs, &hd_inners);
  963. X      if( recs != nil )  ExpandRecursives(recs);
  964. X      if( need_precedes )        /* need an ordering constraint */
  965. X      {    OBJECT index1 = New(PRECEDES);
  966. X    OBJECT index2 = New(FOLLOWS);
  967. X    blocked(index2) = FALSE;
  968. X    tmp = MakeWord("", no_fpos);
  969. X    Link(index1, tmp);  Link(index2, tmp);
  970. X    Link(Up(index), index1);
  971. X    Link(Down(hd), index2);
  972. X    debug0(DGA, D, "  inserting PRECEDES and FOLLOWS");
  973. X      }
  974. X      LeaveErrorBlock(TRUE);
  975. X    }
  976. X    if( !FitsConstraint(back(hd, COL), fwd(hd, COL), c) )
  977. X    { debug3(DGA, D, "  reject: hd %s,%s does not fit target_galley %s",
  978. X    EchoLength(back(hd, COL)), EchoLength(fwd(hd, COL)),
  979. X    EchoConstraint(&c));
  980. X      Error(WARN, &fpos(hd),"too little horizontal space for galley %s at %s",
  981. X    SymName(actual(hd)), SymName(actual(dest)));
  982. X      goto REJECT;
  983. X    }
  984. X
  985. X    /* check status of first component of hd */
  986. X    debug0(DGA, DD, "  now ready to attach; hd =");
  987. X    ifdebug(DGA, DD, EchoObject(stderr, hd));
  988. X    for( link = Down(hd);  link != hd;  link = NextDown(link) )
  989. X    {
  990. X      Child(y, link);
  991. X      debug1(DGA, DD, "  examining %s", EchoObject(null, y));
  992. X      if( type(y) == SPLIT )  Child(y, DownDim(y, ROW));
  993. X      switch( type(y) )
  994. X      {
  995. X
  996. X    case EXPAND_IND:
  997. X    case GALL_PREC:
  998. X    case GALL_FOLL:
  999. X    case GALL_TARG:
  1000. X    case CROSS_PREC:
  1001. X    case CROSS_FOLL:
  1002. X    case CROSS_TARG:
  1003. X        
  1004. X      break;
  1005. X
  1006. X
  1007. X    case PRECEDES:
  1008. X    case UNATTACHED:
  1009. X        
  1010. X      if( was_sized )
  1011. X      { /* SizeGalley was not called, so hd_inners was not set by it */
  1012. X        if( hd_inners == nil )  hd_inners = New(ACAT);
  1013. X        Link(hd_inners, y);
  1014. X      }
  1015. X      break;
  1016. X
  1017. X
  1018. X    case RECEPTIVE:
  1019. X
  1020. X      if( non_blocking(y) )
  1021. X      { link = PrevDown(link);
  1022. X        DeleteNode(y);
  1023. X      }
  1024. X      else goto SUSPEND;
  1025. X      break;
  1026. X
  1027. X
  1028. X    case RECEIVING:
  1029. X        
  1030. X      if( non_blocking(y) )
  1031. X      { while( Down(y) != y )
  1032. X        { Child(z, Down(y));
  1033. X          DetachGalley(z);
  1034. X          KillGalley(z);
  1035. X        }
  1036. X        link = PrevDown(link);
  1037. X        DeleteNode(y);
  1038. X      }
  1039. X      else goto SUSPEND;
  1040. X      break;
  1041. X
  1042. X
  1043. X    case FOLLOWS:
  1044. X        
  1045. X      Child(tmp, Down(y));
  1046. X      if( Up(tmp) == LastUp(tmp) )
  1047. X      { link = pred(link, CHILD);
  1048. X        debug0(DGA, DD, "  disposing FOLLOWS");
  1049. X        DisposeChild(NextDown(link));
  1050. X        break;
  1051. X      }
  1052. X      Parent(tmp, Up(tmp));
  1053. X      assert(type(tmp) == PRECEDES, "Attach: PRECEDES!");
  1054. X      switch( CheckConstraint(tmp, target_index) )
  1055. X      {
  1056. X        case CLEAR:        DeleteNode(tmp);
  1057. X                link = pred(link, CHILD);
  1058. X                DisposeChild(NextDown(link));
  1059. X                break;
  1060. X
  1061. X        case PROMOTE:    break;
  1062. X
  1063. X        case BLOCK:        debug0(DGA, DD, "CheckContraint: BLOCK");
  1064. X                goto SUSPEND;
  1065. X
  1066. X        case CLOSE:        debug0(DGA, D, "  reject: CheckContraint");
  1067. X                goto REJECT;
  1068. X      }
  1069. X      break;
  1070. X
  1071. X
  1072. X    case GAP_OBJ:
  1073. X
  1074. X      if( !join(gap(y)) )  seen_nojoin(hd) = TRUE;
  1075. X      break;
  1076. X
  1077. X
  1078. X    case CLOSURE:
  1079. X    case NULL_CLOS:
  1080. X    case CROSS:
  1081. X
  1082. X      break;
  1083. X
  1084. X
  1085. X    case WORD:
  1086. X    case ONE_COL:
  1087. X    case ONE_ROW:
  1088. X    case WIDE:
  1089. X    case HIGH:
  1090. X    case HSCALE:
  1091. X    case VSCALE:
  1092. X    case HCONTRACT:
  1093. X    case VCONTRACT:
  1094. X    case HEXPAND:
  1095. X    case VEXPAND:
  1096. X    case PADJUST:
  1097. X    case HADJUST:
  1098. X    case VADJUST:
  1099. X    case ROTATE:
  1100. X    case SCALE:
  1101. X    case INCGRAPHIC:
  1102. X    case SINCGRAPHIC:
  1103. X    case GRAPHIC:
  1104. X    case ACAT:
  1105. X    case HCAT:
  1106. X    case ROW_THR:
  1107. X        
  1108. X      /* make sure y is not joined to a target below */
  1109. X      for( zlink = NextDown(link);  zlink != hd;  zlink = NextDown(zlink) )
  1110. X      { Child(z, zlink);
  1111. X        switch( type(z) )
  1112. X        {
  1113. X          case RECEPTIVE:    if( non_blocking(z) )
  1114. X                { zlink = PrevDown(zlink);
  1115. X                  DeleteNode(z);
  1116. X                }
  1117. X                else
  1118. X                { y = z;
  1119. X                  goto SUSPEND;
  1120. X                }
  1121. X                break;
  1122. X
  1123. X          case RECEIVING:    if( non_blocking(z) )
  1124. X                { zlink = PrevDown(zlink);
  1125. X                  while( Down(z) != z )
  1126. X                  { Child(tmp, Down(y));
  1127. X                    DetachGalley(tmp);
  1128. X                    KillGalley(tmp);
  1129. X                  }
  1130. X                  DeleteNode(z);
  1131. X                }
  1132. X                else
  1133. X                { y = z;
  1134. X                  goto SUSPEND;
  1135. X                }
  1136. X                break;
  1137. X
  1138. X          case GAP_OBJ:    if( !join(gap(z)) )  zlink = PrevDown(hd);
  1139. X                break;
  1140. X
  1141. X          default:        break;
  1142. X        }
  1143. X      }
  1144. X
  1145. X      /* check availability of vertical space for the first component */
  1146. X      if( !external(dest) )
  1147. X      { Constrained(dest, &c, ROW);
  1148. X        debug2(DSC, D, "Constrained( %s, ROW ) = %s",
  1149. X            EchoObject(null, dest), EchoConstraint(&c));
  1150. X        if( !FitsConstraint(back(y, ROW), fwd(y, ROW), c) )
  1151. X        { Error(WARN, &fpos(y),
  1152. X        "insufficient vertical space for this component of %s in %s",
  1153. X        SymName(actual(hd)), SymName(actual(dest)));
  1154. X          debug3(DGA, D, "  reject: vsize %s,%s in %s; y=",
  1155. X        EchoLength(back(y, ROW)), EchoLength(fwd(y, ROW)),
  1156. X        EchoConstraint(&c));
  1157. X          ifdebug(DGA, D, EchoObject(stderr, y));
  1158. X          goto REJECT;
  1159. X        }
  1160. X        debug0(DSA, D, "calling AdjustSize from AttachGalley (a)");
  1161. X        AdjustSize(dest, back(y, ROW), fwd(y, ROW), ROW);
  1162. X      }
  1163. X      if( !external(target) )
  1164. X      { Constrained(target, &c, ROW);
  1165. X        debug2(DSC, D, "Constrained( %s, ROW ) = %s",
  1166. X            EchoObject(null, target), EchoConstraint(&c));
  1167. X        Child(z, LastDown(target_galley));
  1168. X        assert( !is_index(type(z)), "AttachGalley: is_index(z)!" );
  1169. X        assert( back(z, ROW) >= 0 && fwd(z, ROW) >= 0,
  1170. X            "AttachGalley: negative z sizes!" );
  1171. X        if( !FitsConstraint(back(z, ROW), fwd(z, ROW), c) )
  1172. X        { Error(WARN, &fpos(y),
  1173. X        "insufficient vertical space for this component of %s in %s",
  1174. X        SymName(actual(hd)), SymName(actual(target)));
  1175. X          debug3(DGA, D, "  reject: size was %s,%s in %s; y =",
  1176. X        EchoLength(back(z, ROW)), EchoLength(fwd(z, ROW)),
  1177. X        EchoConstraint(&c));
  1178. X          ifdebug(DGA, D, EchoObject(stderr, y));
  1179. X          goto REJECT;
  1180. X        }
  1181. X        debug0(DSA, D, "calling AdjustSize from AttachGalley (b)");
  1182. X        AdjustSize(target, back(z, ROW), fwd(z, ROW), ROW);
  1183. X      }
  1184. X      goto ACCEPT;
  1185. X
  1186. X
  1187. X    default:
  1188. X        
  1189. X      Error(INTERN, &fpos(y), "AttachGalley: %s", Image(type(y)));
  1190. X      break;
  1191. X
  1192. X      } /* end switch */
  1193. X    } /* end for */
  1194. X
  1195. X    /* empty galley; promote any indexes, kill the galley, and exit */
  1196. X    /* this bypasses target_galley, which is not expanded in the empty case */
  1197. X    debug0(DGA, D, "  empty galley");
  1198. X    if( tg_inners != nil )  DisposeObject(tg_inners), tg_inners = nil;
  1199. X    DisposeObject(target_galley);
  1200. X    LeaveErrorBlock(FALSE);
  1201. X    if( LastDown(hd) != hd )  Promote(hd, hd, target_index);
  1202. X    debug0(DGA, D, "calling KillGalley from AttachGalley (b)");
  1203. X    KillGalley(hd);
  1204. X
  1205. X    /* return; only hd_inners needs to be flushed now */
  1206. X    *inners = hd_inners;
  1207. X    debug0(DGA, D, "]AttachGalley returning killed: empty galley");
  1208. X    return;
  1209. X
  1210. X
  1211. X    REJECT:
  1212. X    
  1213. X      /* reject first component */
  1214. X      LeaveErrorBlock(TRUE);
  1215. X      if( tg_inners != nil )  DisposeObject(tg_inners), tg_inners = nil;
  1216. X      DisposeObject(target_galley);
  1217. X      if( backward(hd) && !sized(hd) )
  1218. X      {
  1219. X    /* move to just before the failed target */
  1220. X    MoveLink(Up(index), Up(target_index), PARENT);
  1221. X      }
  1222. X      else
  1223. X      {
  1224. X    /* move to just after the failed target */
  1225. X    MoveLink(Up(index), NextDown(Up(target_index)), PARENT);
  1226. X      }
  1227. X      continue;
  1228. X
  1229. X
  1230. X    SUSPEND:
  1231. X    
  1232. X      /* suspend at first component */
  1233. X      debug1(DGA, D, "  suspend %s", EchoObject(null, y));
  1234. X      blocked(y) = TRUE;
  1235. X      LeaveErrorBlock(FALSE);
  1236. X      if( tg_inners != nil )  DisposeObject(tg_inners), tg_inners = nil;
  1237. X      DisposeObject(target_galley);
  1238. X      MoveLink(Up(index), Up(target_index), PARENT);
  1239. X      if( was_sized )
  1240. X      { /* nothing new to flush if suspending and already sized */
  1241. X    if( hd_inners != nil )  DisposeObject(hd_inners), hd_inners = nil;
  1242. X      }
  1243. X      else
  1244. X      { /* flush newly discovered inners if not sized before */
  1245. X    *inners = hd_inners;
  1246. X      }
  1247. X      debug0(DGA, D, "]AttachGalley returning: suspending.");
  1248. X      return;
  1249. X
  1250. X
  1251. X    ACCEPT:
  1252. X    
  1253. X      /* accept first component; now committed to the attach */
  1254. X      debug1(DGA, D, "  accept %s", EchoObject(null, y));
  1255. X      LeaveErrorBlock(TRUE);
  1256. X
  1257. X      /* adjust horizontal sizes */
  1258. X      debug0(DSA, D, "calling AdjustSize from AttachGalley (c)");
  1259. X      AdjustSize(dest, back(hd, COL), fwd(hd, COL), COL);
  1260. X      debug0(DSA, D, "calling AdjustSize from AttachGalley (d)");
  1261. X      AdjustSize(target, back(target_galley, COL),
  1262. X                fwd(target_galley, COL), COL);
  1263. X        
  1264. X      /* attach hd to dest */
  1265. X      MoveLink(Up(hd), dest_index, PARENT);
  1266. X      assert( type(index) == UNATTACHED, "AttachGalley: type(index)!" );
  1267. X      DeleteNode(index);
  1268. X
  1269. X      /* move first component of hd into dest */
  1270. X      /* nb Interpose must be done after all AdjustSize calls */
  1271. X      if( !external(dest) )   Interpose(dest, VCAT, hd, y);
  1272. X      Promote(hd, NextDown(link), dest_index);
  1273. X
  1274. X      /* move target_galley into target */
  1275. X      /* nb Interpose must be done after all AdjustSize calls */
  1276. X      if( !external(target) )
  1277. X      {    Child(z, LastDown(target_galley));
  1278. X    Interpose(target, VCAT, z, z);
  1279. X      }
  1280. X      Promote(target_galley, target_galley, target_index);
  1281. X      DeleteNode(target_galley);
  1282. X      assert(Down(target_index)==target_index, "AttachGalley: target_ind");
  1283. X      if( blocked(target_index) )  blocked(dest_index) = TRUE;
  1284. X      DeleteNode(target_index);
  1285. X
  1286. X      /* return; both tg_inners and hd_inners need to be flushed now;        */
  1287. X      /* if was_sized, hd_inners contains the inners of the first component; */
  1288. X      /* otherwise it contains the inners of all components, from SizeGalley */
  1289. X      if( tg_inners == nil ) *inners = hd_inners;
  1290. X      else if( hd_inners == nil ) *inners = tg_inners;
  1291. X      else
  1292. X      {    TransferLinks(Down(hd_inners), hd_inners, tg_inners);
  1293. X    DeleteNode(hd_inners);
  1294. X    *inners = tg_inners;
  1295. X      }
  1296. X      debug0(DGA, D, "]AttachGalley returning (accept)");
  1297. X      return;
  1298. X
  1299. X  } /* end for */
  1300. X} /* end AttachGalley */
  1301. X
  1302. X
  1303. X/*****************************************************************************/
  1304. X/*                                                                           */
  1305. X/*  DetachGalley(hd)                                                         */
  1306. X/*                                                                           */
  1307. X/*  Detach galley hd from its target.                                        */
  1308. X/*                                                                           */
  1309. X/*****************************************************************************/
  1310. X
  1311. XDetachGalley(hd)
  1312. XOBJECT hd;
  1313. X{ OBJECT prnt, index;
  1314. X  debug1(DGA, D, "DetachGalley( %s )", EchoObject(null, hd));
  1315. X  assert( type(hd) == HEAD && Up(hd) != hd, "DetachGalley: precondition!" );
  1316. X  Parent(prnt, Up(hd));
  1317. X  assert( Up(prnt) != prnt, "DetachGalley: parent!" );
  1318. X  index = New(UNATTACHED);
  1319. X  MoveLink(Up(hd), index, PARENT);
  1320. X  Link(NextDown(Up(prnt)), index);
  1321. X  debug0(DGA, D, "DetachGalley returning.");
  1322. X} /* end DetachGalley */
  1323. END_OF_FILE
  1324.   if test 22219 -ne `wc -c <'lout/z19.c'`; then
  1325.     echo shar: \"'lout/z19.c'\" unpacked with wrong size!
  1326.   fi
  1327.   # end of 'lout/z19.c'
  1328. fi
  1329. if test -f 'lout/z23.c' -a "${1}" != "-c" ; then 
  1330.   echo shar: Will not clobber existing file \"'lout/z23.c'\"
  1331. else
  1332.   echo shar: Extracting \"'lout/z23.c'\" \(28465 characters\)
  1333.   sed "s/^X//" >'lout/z23.c' <<'END_OF_FILE'
  1334. X/*@z23.c:Galley Printer:FixAndPrintObject@************************************/
  1335. X/*                                                                           */
  1336. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  1337. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  1338. X/*                                                                           */
  1339. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  1340. X/*  Basser Department of Computer Science                                    */
  1341. X/*  The University of Sydney 2006                                            */
  1342. X/*  AUSTRALIA                                                                */
  1343. X/*                                                                           */
  1344. X/*  This program is free software; you can redistribute it and/or modify     */
  1345. X/*  it under the terms of the GNU General Public License as published by     */
  1346. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  1347. X/*  any later version.                                                       */
  1348. X/*                                                                           */
  1349. X/*  This program is distributed in the hope that it will be useful,          */
  1350. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  1351. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  1352. X/*  GNU General Public License for more details.                             */
  1353. X/*                                                                           */
  1354. X/*  You should have received a copy of the GNU General Public License        */
  1355. X/*  along with this program; if not, write to the Free Software              */
  1356. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  1357. X/*                                                                           */
  1358. X/*  FILE:         z23.c                                                      */
  1359. X/*  MODULE:       Galley Printer                                             */
  1360. X/*  EXTERNS:      FixAndPrintObject()                                        */
  1361. X/*                                                                           */
  1362. X/*****************************************************************************/
  1363. X#include "externs"
  1364. X#define    NO_SUPPRESS    FALSE
  1365. X#define    SUPPRESS    TRUE
  1366. X#define    ALL_ADJUST    2
  1367. X#define    LAST_ADJUST    1
  1368. X#define    ALL_ADJUST    2
  1369. X
  1370. X#define CountChild(y, link, i)                        \
  1371. Xfor( y=pred(link, PARENT), i=1; type(y)==LINK;  y = pred(y, PARENT), i++ )
  1372. X
  1373. X
  1374. X/*****************************************************************************/
  1375. X/*                                                                           */
  1376. X/*  static float ScaleFactor(avail_size, inner_size)                         */
  1377. X/*                                                                           */
  1378. X/*  Return the scale factor for this scaling, or 0 if impossible.            */
  1379. X/*                                                                           */
  1380. X/*****************************************************************************/
  1381. X
  1382. Xstatic float ScaleFactor(avail_size, inner_size)
  1383. XLENGTH avail_size, inner_size;
  1384. X{ float scale_factor;
  1385. X  scale_factor = avail_size <= 0 ? 0 :
  1386. X         inner_size <= 0 ? 0 : (float) avail_size / inner_size;
  1387. X  return scale_factor;
  1388. X}
  1389. X
  1390. X
  1391. X/*****************************************************************************/
  1392. X/*                                                                           */
  1393. X/*  static LENGTH FindAdjustIncrement(x, frame_size, dim)                    */
  1394. X/*                                                                           */
  1395. X/*  Find the amount by which to increase the width of the subobjects of      */
  1396. X/*  concatenation object x so that it is adjusted to fill size frame_size.   */
  1397. X/*                                                                           */
  1398. X/*****************************************************************************/
  1399. X
  1400. Xstatic LENGTH FindAdjustIncrement(x, frame_size, dim)
  1401. XOBJECT x;  LENGTH frame_size;  int dim;
  1402. X{ OBJECT y, link, prev, g;
  1403. X  int adjustable_gaps;
  1404. X  LENGTH inc, mk, actual_size;
  1405. X
  1406. X  debug2(DGP, D, "FindAdjustIncrement(x, %s, %s)",
  1407. X    EchoLength(frame_size), dimen(dim));
  1408. X  FirstDefinite(x, link, prev);
  1409. X  if( link != x )
  1410. X  { adjustable_gaps = 0;
  1411. X    mk = back(prev, dim);
  1412. X    NextDefiniteWithGap(x, link, y, g);
  1413. X    while( link != x )
  1414. X    { if ( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
  1415. X                    || units(gap(g)) == FRAME_UNIT )
  1416. X      {    debug0(DGP, D, "FindAdjustIncrement returning 0 (tab gap)");
  1417. X    return 0;
  1418. X      }
  1419. X      mk += ActualGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g),
  1420. X        frame_size, mk);
  1421. X      prev = y;
  1422. X      adjustable_gaps++;
  1423. X      NextDefiniteWithGap(x, link, y, g);
  1424. X    }
  1425. X    actual_size = mk + fwd(prev, dim);
  1426. X    debug2(DGP, DD, "  actual_size = %s, adjustable_gaps = %d",
  1427. X    EchoLength(actual_size), adjustable_gaps);
  1428. X    inc = adjustable_gaps==0 ? 0 : (frame_size - actual_size) / adjustable_gaps;
  1429. X  }
  1430. X  else inc = 0;
  1431. X  debug1(DGP, D, "FindAdjustIncrement returning %s", EchoLength(inc));
  1432. X  return inc;
  1433. X} /* end FindAdjustIncrement *.
  1434. X
  1435. X
  1436. X/*****************************************************************************/
  1437. X/*                                                                           */
  1438. X/*  FixAndPrintObject(x, xmk, xb, xf, dim, adjust, suppress, padj, pg,count) */
  1439. X/*                                                                           */
  1440. X/*  Fix the absolute position of object x in dimension dim, in such a way    */
  1441. X/*  that the principal mark of x has coordinate xmk, and x has actual size   */
  1442. X/*  (xb, xf), where xb >= back(x, dim) and xf >= fwd(x, dim).                */
  1443. X/*                                                                           */
  1444. X/*  Actually, in the case where x includes an object lying on a thread       */
  1445. X/*  leading outside x, the final size of x may be different.  Because        */
  1446. X/*  of this, the procedure sets back(x, dim) and fwd(x, dim) to the actual   */
  1447. X/*  size of x upon return.  The caller assumes that x will exactly occupy    */
  1448. X/*  this space back(x, dim), fwd(x, dim).                                    */
  1449. X/*                                                                           */
  1450. X/*  If x does not fill the forward part of the space allocated to it, the    */
  1451. X/*  adjust parameter determines what, if anything, to do about this.  The    */
  1452. X/*  two possible values of this parameter are:                               */
  1453. X/*                                                                           */
  1454. X/*    LAST_ADJUST        Adjust x to fill the forward space available to     */
  1455. X/*                       it, by adjusting the last component if x is a       */
  1456. X/*                       CAT object, or adjusting the child otherwise.       */
  1457. X/*                                                                           */
  1458. X/*    ALL_ADJUST         Adjust x to fill the forward space available to     */
  1459. X/*                       it, by adjusting all the components if x is a       */
  1460. X/*                       CAT object, or adjusting the child otherwise.       */
  1461. X/*                                                                           */
  1462. X/*  The suppress parameter is true if a temporary suppression of adjustment  */
  1463. X/*  is in effect (because a neighbouring adjustment has already been done).  */
  1464. X/*                                                                           */
  1465. X/*  The padj parameter is analogous to the adjust parameter, but it          */
  1466. X/*  applies only to & adjustment, not to | or / adjustment.                  */
  1467. X/*                                                                           */
  1468. X/*  If dim == COL, the coordinate information is merely stored; but if       */
  1469. X/*  dim == ROW, it is used to generate PostScript for printing x.            */
  1470. X/*                                                                           */
  1471. X/*  Parameter pg records the height of the current page.  This is used       */
  1472. X/*  to correct for the fact that Lout's origin is at the top left, while     */
  1473. X/*  PostScript's is at the bottom left.  This correction cannot be made by   */
  1474. X/*  transforming user space.                                                 */
  1475. X/*                                                                           */
  1476. X/*  x is the count'th child of its parent (used by COL_THR and ROW_THR only) */
  1477. X/*                                                                           */
  1478. X/*****************************************************************************/
  1479. X
  1480. XFixAndPrintObject(x, xmk, xb, xf, dim, adjust, suppress, padj, pg, count)
  1481. XOBJECT x;  LENGTH xmk, xb, xf; int dim, adjust;  BOOLEAN suppress;
  1482. Xint padj;  LENGTH pg;  int count;
  1483. X{ OBJECT y, link, prev, g, uplink, z, p;
  1484. X  LENGTH mk, frame_size, back_edge, tb, tf, yb, yf, inc;
  1485. X  int i; float scale_factor;
  1486. X  debug8(DGP, D, "[ FixAndPrintObject(%s, %s, %s,%s, %s, %s, %s, %s, pg ), x =",
  1487. X    Image(type(x)), EchoLength(xmk), EchoLength(xb), EchoLength(xf), dimen(dim),
  1488. X    (adjust == LAST_ADJUST ? "last_adjust" : "all_adjust"),
  1489. X    (suppress == SUPPRESS ? "suppress" : "no_suppress"),
  1490. X    (padj   == LAST_ADJUST ? "last_adjust" : "all_adjust"));
  1491. X  ifdebug(DGP, DD, EchoObject(stderr, x));
  1492. X
  1493. X  switch( type(x) )
  1494. X  {
  1495. X
  1496. X    case CLOSURE:
  1497. X    case NULL_CLOS:
  1498. X    case CROSS:
  1499. X    
  1500. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1501. X      break;
  1502. X
  1503. X
  1504. X    case WORD:
  1505. X    
  1506. X      if( dim == COL )  word_save_mark(x) = xmk;
  1507. X      else if( string(x)[0] != '\0' )  PrintAtom(x, word_save_mark(x), pg-xmk);
  1508. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1509. X      break;
  1510. X
  1511. X
  1512. X    case WIDE:
  1513. X    case HIGH:
  1514. X    
  1515. X      CountChild(y, Down(x), count);
  1516. X      if( (dim == COL) == (type(x) == WIDE) )
  1517. X      { yf = bfc(constraint(x)) - back(y, dim);
  1518. X        FixAndPrintObject(y, xmk, back(y,dim), yf, dim, LAST_ADJUST,
  1519. X        NO_SUPPRESS, padj, pg, count);
  1520. X        back(x, dim) = xb;  fwd(x, dim) = xf;
  1521. X      }
  1522. X      else
  1523. X      {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress,
  1524. X      padj, pg, count);
  1525. X    back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  1526. X      }
  1527. X      break;
  1528. X
  1529. X
  1530. X    case HCONTRACT:
  1531. X    case VCONTRACT:
  1532. X    
  1533. X      CountChild(y, Down(x), count);
  1534. X      if( (dim == COL) == (type(x) == HCONTRACT) )
  1535. X      {    FixAndPrintObject(y, xmk, back(y,dim), fwd(y,dim), dim, LAST_ADJUST,
  1536. X      NO_SUPPRESS, padj, pg, count);
  1537. X        back(x, dim) = xb;  fwd(x, dim) = xf;
  1538. X      }
  1539. X      else
  1540. X      {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress, padj,pg,count);
  1541. X        back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  1542. X      }
  1543. X      break;
  1544. X
  1545. X
  1546. X    case ONE_COL:
  1547. X    case ONE_ROW:
  1548. X    case HEXPAND:
  1549. X    case VEXPAND:
  1550. X    
  1551. X      CountChild(y, Down(x), count);
  1552. X      if( (dim == COL) == (type(x) == ONE_COL || type(x) == HEXPAND) )
  1553. X      { FixAndPrintObject(y, xmk, xb, xf, dim, LAST_ADJUST,
  1554. X        NO_SUPPRESS, padj, pg, count);
  1555. X        back(x, dim) = xb;  fwd(x, dim) = xf;
  1556. X      }
  1557. X      else
  1558. X      {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress, padj,pg,count);
  1559. X    back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  1560. X      }
  1561. X      break;
  1562. X
  1563. X
  1564. X    case PADJUST:
  1565. X    
  1566. X      CountChild(y, Down(x), count);
  1567. X      FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress,
  1568. X    ALL_ADJUST, pg, count);
  1569. X      back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  1570. X      break;
  1571. X
  1572. X
  1573. X    case HADJUST:
  1574. X    case VADJUST:
  1575. X    
  1576. X      CountChild(y, Down(x), count);
  1577. X      if( (dim == COL) == (type(x) == HADJUST) )
  1578. X      {    FixAndPrintObject(y, xmk, xb, xf, dim, ALL_ADJUST, suppress,
  1579. X      padj, pg, count);
  1580. X        back(x, dim) = xb;  fwd(x, dim) = xf;
  1581. X      }
  1582. X      else
  1583. X      {    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress,
  1584. X      padj, pg, count);
  1585. X    back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  1586. X      }
  1587. X      break;
  1588. X
  1589. X
  1590. X    case VSCALE:
  1591. X
  1592. X      debug0(DRS, D, "FixAndPrintObject at VSCALE");
  1593. X      CountChild(y, Down(x), count);
  1594. X      if( dim == COL )
  1595. X      {    FixAndPrintObject(y, xmk, xb, xf, dim, LAST_ADJUST, NO_SUPPRESS,
  1596. X        padj,pg,count);
  1597. X      }
  1598. X      else if( (scale_factor = ScaleFactor(xb+xf, size(y, ROW))) > 0 )
  1599. X      {    SaveGraphicState();
  1600. X    CoordTranslate(0, pg - (xmk-xb + (LENGTH) (back(y, ROW)*scale_factor)));
  1601. X    CoordScale(1.0, scale_factor);
  1602. X        FixAndPrintObject(y, 0, back(y, ROW), fwd(y, ROW), dim, LAST_ADJUST,
  1603. X        NO_SUPPRESS, padj, 0, count);
  1604. X    RestoreGraphicState();
  1605. X      }
  1606. X      else if( type(y) != WORD || string(y)[0] != '\0' )
  1607. X      {    Error(WARN, &fpos(x), "object deleted: cannot %s", KW_VSCALE);
  1608. X      }
  1609. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1610. X      break;
  1611. X
  1612. X
  1613. X    case HSCALE:
  1614. X    
  1615. X      debug0(DRS, DD, "FixAndPrintObject at HSCALE");
  1616. X      CountChild(y, Down(x), count);
  1617. X      if( dim == COL )
  1618. X      {    save_mark(x) = xmk;
  1619. X    bc(constraint(x)) = xb;
  1620. X    fc(constraint(x)) = xf;
  1621. X        if( (scale_factor = ScaleFactor(xb+xf, size(y, COL))) > 0 )
  1622. X      FixAndPrintObject(y, 0, back(y, COL), fwd(y, COL), dim, LAST_ADJUST,
  1623. X        NO_SUPPRESS, LAST_ADJUST, pg, count);
  1624. X        else if( type(y) != WORD || string(y)[0] != '\0' )
  1625. X      Error(WARN, &fpos(y), "object deleted: cannot %s", KW_HSCALE);
  1626. X      }
  1627. X      else if( (scale_factor =
  1628. X    ScaleFactor(bc(constraint(x))+fc(constraint(x)), size(y, COL))) > 0 )
  1629. X      {    SaveGraphicState();
  1630. X    CoordTranslate(save_mark(x) - bc(constraint(x))
  1631. X       + (LENGTH) (back(y, COL)*scale_factor), 0);
  1632. X    CoordScale(scale_factor, 1.0);
  1633. X        FixAndPrintObject(y, xmk, xb, xf, dim, LAST_ADJUST,
  1634. X        NO_SUPPRESS, padj, pg, count);
  1635. X    RestoreGraphicState();
  1636. X      }
  1637. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1638. X      break;
  1639. X
  1640. X
  1641. X    case SCALE:
  1642. X
  1643. X      CountChild(y, Down(x), count);
  1644. X      if( dim == COL )
  1645. X      {
  1646. X    assert( bc(constraint(x)) > 0, "FAPO: horizontal scale factor!" );
  1647. X    save_mark(x) = xmk;
  1648. X    yb = xb * SF / bc(constraint(x));
  1649. X    yf = xf * SF / bc(constraint(x));
  1650. X        FixAndPrintObject(y, 0, yb, yf, dim, LAST_ADJUST, NO_SUPPRESS,
  1651. X        padj, pg, count);
  1652. X      }
  1653. X      else
  1654. X      {
  1655. X    assert( fc(constraint(x)) > 0, "FAPO: vertical scale factor!" );
  1656. X    yb = xb * SF / fc(constraint(x));
  1657. X    yf = xf * SF / fc(constraint(x));
  1658. X    SaveGraphicState();
  1659. X    CoordTranslate(save_mark(x), pg - xmk);
  1660. X    CoordScale( (float) bc(constraint(x))/SF, (float) fc(constraint(x))/SF);
  1661. X        FixAndPrintObject(y, 0, yb, yf, dim, LAST_ADJUST, NO_SUPPRESS,
  1662. X        padj,0,count);
  1663. X    RestoreGraphicState();
  1664. X      }
  1665. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1666. X      break;
  1667. X
  1668. X
  1669. X    case ROTATE:
  1670. X    
  1671. X      CountChild(y, Down(x), count);
  1672. X      if( dim == COL )
  1673. X      {    save_mark(x) = xmk;
  1674. X    back(x, dim) = xb;
  1675. X    fwd(x, dim)  = xf;
  1676. X      }
  1677. X      else
  1678. X      {
  1679. X    CONSTRAINT colc, rowc, yc;
  1680. X    back(x, dim) = xb;
  1681. X    fwd(x, dim)  = xf;
  1682. X    SetConstraint(colc, back(x,COL), MAX_LEN, fwd(x,COL));
  1683. X    SetConstraint(rowc, back(x,ROW), MAX_LEN, fwd(x,ROW));
  1684. X    RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc, COL);
  1685. X    FixAndPrintObject(y, 0, bc(yc), fc(yc), COL, LAST_ADJUST,
  1686. X        NO_SUPPRESS, padj, pg, count);
  1687. X    SaveGraphicState();
  1688. X    CoordTranslate(save_mark(x), pg - xmk);
  1689. X    CoordRotate(sparec(constraint(x)));
  1690. X    RotateConstraint(&yc, y, sparec(constraint(x)), &colc, &rowc, ROW);
  1691. X    FixAndPrintObject(y, 0, bc(yc), fc(yc), ROW, LAST_ADJUST,
  1692. X        NO_SUPPRESS, padj, 0, count);
  1693. X    RestoreGraphicState();
  1694. X      }
  1695. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1696. X      break;
  1697. X
  1698. X
  1699. X    case GRAPHIC:
  1700. X    
  1701. X      CountChild(y, LastDown(x), count);
  1702. X      if( dim == COL )
  1703. X      {
  1704. X    back(x, dim) = xb;
  1705. X    fwd(x, dim)  = xf;
  1706. X    debug2(DGP, DD, "GRAPHIC COL storing size %s, %s",
  1707. X      EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
  1708. X    save_mark(x) = xmk - back(x, COL);
  1709. X        FixAndPrintObject(y, xb, xb, xf, dim, LAST_ADJUST,
  1710. X        NO_SUPPRESS, padj, pg, count);
  1711. X      }
  1712. X      else
  1713. X      { OBJECT tmp, pre, post;
  1714. X        Child(tmp, Down(x));
  1715. X        if( type(tmp) == VCAT )
  1716. X        { Child(pre, Down(tmp));
  1717. X          Child(post, LastDown(tmp));
  1718. X        }
  1719. X        else pre = tmp, post = nil;
  1720. X    back(x, dim) = xb;
  1721. X    fwd(x, dim)  = xf;
  1722. X        SaveGraphicState();
  1723. X        CoordTranslate(save_mark(x), pg - (xmk + fwd(x, ROW)));
  1724. X    debug4(DGP, DD, "GRAPHIC ROW calling %s,%s %s,%s",
  1725. X      EchoLength(back(x, COL)), EchoLength(fwd(x, COL)),
  1726. X      EchoLength(back(x, ROW)), EchoLength(fwd(x, ROW)));
  1727. X        DefineGraphicNames(x);
  1728. X        SaveGraphicState();
  1729. X        PrintGraphicObject(pre);
  1730. X        RestoreGraphicState();
  1731. X        FixAndPrintObject(y, xb, xb, xf, dim, LAST_ADJUST,
  1732. X        NO_SUPPRESS, padj, xb + xf, count);
  1733. X        if( post != nil )  PrintGraphicObject(post);
  1734. X        RestoreGraphicState();
  1735. X      }
  1736. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1737. X      break;
  1738. X
  1739. X
  1740. X    case INCGRAPHIC:
  1741. X    case SINCGRAPHIC:
  1742. X
  1743. X      CountChild(y, Down(x), count);
  1744. X      if( dim == COL )
  1745. X      {    save_mark(x) = xmk;
  1746. X      }
  1747. X      else if( sparec(constraint(x)) )
  1748. X      {
  1749. X    PrintGraphicInclude(x, save_mark(x), pg - xmk);
  1750. X      }
  1751. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  1752. X      break;
  1753. X
  1754. X
  1755. X    case SPLIT:
  1756. X    
  1757. X      link = DownDim(x, dim);  CountChild(y, link, count);
  1758. X      FixAndPrintObject(y, xmk, xb, xf, dim, adjust, suppress, padj, pg, count);
  1759. X      back(x, dim) = back(y, dim);  fwd(x, dim) = fwd(y, dim);
  1760. X      break;
  1761. X
  1762. X
  1763. X    case VCAT:
  1764. X    case HCAT:
  1765. X
  1766. X      if( (type(x) == VCAT) == (dim == ROW) )
  1767. X      { 
  1768. X    /* find adjustment increment if required */
  1769. X    frame_size = xb + xf;
  1770. X    if( adjust == ALL_ADJUST && !suppress )
  1771. X      inc = FindAdjustIncrement(x, frame_size, dim);
  1772. X    else inc = 0;
  1773. X
  1774. X    FirstDefinite(x, link, prev);
  1775. X    if( link != x )
  1776. X    { back_edge = xmk - back(x, dim);
  1777. X      mk = back_edge + back(prev, dim);
  1778. X      NextDefiniteWithGap(x, link, y, g);
  1779. X      while( link != x )
  1780. X      {
  1781. X        FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim) + inc,
  1782. X          dim, adjust, NO_SUPPRESS, padj, pg, count);
  1783. X        /* NB fwd(prev, dim) may be changed by the call to FAPO */
  1784. X        mk += ActualGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g),
  1785. X            frame_size, mk - back_edge);
  1786. X        prev = y;
  1787. X        NextDefiniteWithGap(x, link, y, g);
  1788. X      }
  1789. X      if( suppress )
  1790. X        FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim),
  1791. X          dim, adjust, NO_SUPPRESS, padj, pg, count);
  1792. X      else
  1793. X        FixAndPrintObject(prev, mk, back(prev,dim),
  1794. X          max(fwd(prev, dim), back_edge+frame_size-mk),
  1795. X          dim, adjust, NO_SUPPRESS, padj, pg, count);
  1796. X      back(x, dim) = max(back(x, dim), xb);
  1797. X      fwd(x, dim) = mk + fwd(prev, dim) - back_edge - back(x, dim);
  1798. X    }
  1799. X    else back(x, dim) = xb, fwd(x, dim) = xf;
  1800. X      }
  1801. X      else
  1802. X      { OBJECT start_group, zlink, m;  BOOLEAN dble_found;  LENGTH b, f, dlen;
  1803. X    start_group = nil;  dble_found = FALSE;  dlen = 0;
  1804. X    debug0(DGP, DD, "  groups beginning.");
  1805. X    for( link = Down(x);  link != x;  link = NextDown(link) )
  1806. X    {
  1807. X      Child(y, link);
  1808. X      debug1(DGP, DD, "  examining %s", EchoObject(null, y));
  1809. X      if( is_index(type(y)) )  continue;
  1810. X      if( type(y) == GAP_OBJ )
  1811. X      { 
  1812. X        assert( start_group != nil, "FAPO: start_group!" );
  1813. X        if( !join(gap(y)) )
  1814. X        { 
  1815. X          /* finish off and fix this group */
  1816. X          debug2(DGP, DD, "  finishing group: b = %s, f = %s",
  1817. X            EchoLength(b), EchoLength(f));
  1818. X          FixAndPrintObject(m, xmk+b, b, xf-b, dim, adjust,
  1819. X              NO_SUPPRESS, padj, pg, count);
  1820. X          b = back(m, dim);  f = fwd(m, dim);
  1821. X          for( zlink = start_group;  zlink != link;  zlink=NextDown(zlink) )
  1822. X          {    CountChild(z, zlink, count);
  1823. X        if( !is_definite(type(z)) || z == m )  continue;
  1824. X        FixAndPrintObject(z, xmk + b, b, xf - b, dim,
  1825. X              adjust, SUPPRESS, padj, pg, count);
  1826. X        b = max(b, back(z, dim));  f = max(f, fwd(z, dim));
  1827. X          }
  1828. X          dlen = max(dlen, b + f);
  1829. X          dble_found = TRUE;
  1830. X          start_group = nil;
  1831. X        }
  1832. X      }
  1833. X      else if( start_group == nil )
  1834. X      {
  1835. X        /* start new group */
  1836. X        b = back(y, dim);
  1837. X        f = fwd(y, dim);
  1838. X        m = y;
  1839. X        start_group = link;
  1840. X        debug2(DGP, DD, "  starting group: b = %s, f = %s",
  1841. X          EchoLength(b), EchoLength(f));
  1842. X      }
  1843. X      else
  1844. X      {
  1845. X        /* continue with current group */
  1846. X        b = max(b, back(y, dim));
  1847. X        f = max(f, fwd(y, dim));
  1848. X        if( fwd(y, dim) > fwd(m, dim) )  m = y;
  1849. X        debug2(DGP, DD, "  continuing group: b = %s, f = %s",
  1850. X          EchoLength(b), EchoLength(f));
  1851. X      }
  1852. X    }
  1853. X    assert( start_group != nil, "FAPO: final start_group!" );
  1854. X
  1855. X    if( dble_found )
  1856. X    {
  1857. X      /* finish off and fix this last group */
  1858. X      debug2(DGP, DD, "  finishing last group: b = %s, f = %s",
  1859. X          EchoLength(b), EchoLength(f));
  1860. X      FixAndPrintObject(m, xmk + b, b, xf - b, dim, adjust,
  1861. X        NO_SUPPRESS, padj, pg, count);
  1862. X      b = back(m, dim);  f = fwd(m, dim);
  1863. X      for( zlink = start_group;  zlink != link;  zlink = NextDown(zlink) )
  1864. X      { CountChild(z, zlink, count);
  1865. X        if( !is_definite(type(z)) || z == m )  continue;
  1866. X        FixAndPrintObject(z, xmk + b, b, xf - b, dim, adjust,
  1867. X        SUPPRESS, padj, pg, count);
  1868. X        b = max(b, back(z, dim));  f = max(f, fwd(z, dim));
  1869. X      }
  1870. X      dlen = max(dlen, b + f);
  1871. X      back(x, dim) = 0;  fwd(x, dim) = dlen;
  1872. X    }
  1873. X    else
  1874. X    {
  1875. X      /* finish off and fix this last and only group */
  1876. X      debug2(DGP, DD, "  finishing last and only group: b = %s, f = %s",
  1877. X          EchoLength(b), EchoLength(f));
  1878. X      FixAndPrintObject(m, xmk, xb, xf, dim, adjust,
  1879. X         NO_SUPPRESS, padj, pg, count);
  1880. X      b = back(m, dim);  f = fwd(m, dim);
  1881. X      for( zlink = start_group;  zlink != link;  zlink = NextDown(zlink) )
  1882. X      { CountChild(z, zlink, count);
  1883. X        if( !is_definite(type(z)) || z == m )  continue;
  1884. X        FixAndPrintObject(z, xmk, xb, xf, dim, adjust,
  1885. X        SUPPRESS, padj, pg, count);
  1886. X        b = max(b, back(z, dim));  f = max(f, fwd(z, dim));
  1887. X      }
  1888. X      back(x, dim) = b;  fwd(x, dim) = f;
  1889. X    }
  1890. X      }
  1891. X      break;
  1892. X
  1893. X
  1894. X    case ACAT:
  1895. X
  1896. X      if( dim == COL )
  1897. X      { BOOLEAN bad_gap;
  1898. X    LENGTH actual_size,
  1899. X    adjust_indent, frame_size, back_edge, adjust_inc, inc;
  1900. X    int adjustable_gaps;
  1901. X      
  1902. X
  1903. X    /*********************************************************************/
  1904. X    /*                                                                   */
  1905. X    /*  The first step is to calculate the following values:             */
  1906. X    /*                                                                   */
  1907. X    /*    bad_gap          TRUE if an adjust-preventing gap is found     */
  1908. X    /*                                                                   */
  1909. X    /*    actual_size      the actual size of x;                         */
  1910. X    /*                                                                   */
  1911. X    /*    adjustable_gaps  the number of gaps to the right of the        */
  1912. X    /*                     right-most tab gap.                           */
  1913. X    /*                                                                   */
  1914. X    /*  These make it easy to perform adjustment on a second pass, if    */
  1915. X    /*  required.                                                        */
  1916. X    /*                                                                   */
  1917. X    /*********************************************************************/
  1918. X
  1919. X    FirstDefinite(x, link, y);
  1920. X    if( link == x )  break;  /* no definite children, nothing to print */
  1921. X    bad_gap = FALSE;
  1922. X    adjustable_gaps = 0;
  1923. X    back_edge = xmk - xb;
  1924. X    mk = back_edge + back(y, dim);
  1925. X    frame_size = xb + xf;
  1926. X    prev = y;
  1927. X    NextDefiniteWithGap(x, link, y, g);
  1928. X    while( link != x )
  1929. X    {
  1930. X      save_actual_gap(g) = ActualGap(fwd(prev, dim), back(y, dim),
  1931. X        fwd(y, dim), &gap(g), frame_size, mk - back_edge);
  1932. X      mk += save_actual_gap(g);
  1933. X      if( mode(gap(g)) == TAB_MODE || units(gap(g)) == AVAIL_UNIT
  1934. X                       || units(gap(g)) == FRAME_UNIT )
  1935. X      { bad_gap = TRUE;
  1936. X      }
  1937. X      else if( width(gap(g)) > 0 )  adjustable_gaps += 1;
  1938. X      prev = y;
  1939. X      NextDefiniteWithGap(x, link, y, g);
  1940. X    }
  1941. X    actual_size = mk + fwd(prev, dim) - back_edge;
  1942. X
  1943. X    /*********************************************************************/
  1944. X    /*                                                                   */
  1945. X    /*  The second step is to work out whether adjusting is required     */
  1946. X    /*  or not, and if so by how much, using the following variables:    */
  1947. X    /*                                                                   */
  1948. X    /*    adjust_inc       The amount of adjustment to apply initially.  */
  1949. X    /*                                                                   */
  1950. X    /*    adjust_indent    initial indent for centring etc.              */
  1951. X    /*                                                                   */
  1952. X    /*  NB adjust_inc may be negative, if the optimal paragraph          */
  1953. X    /*  breaker has chosen to shrink some gaps.                          */
  1954. X    /*                                                                   */
  1955. X    /*********************************************************************/
  1956. X
  1957. X    adjust_indent = 0;
  1958. X    switch( display_style(save_style(x)) )
  1959. X    {
  1960. X      case DO_ADJUST:    padj = ALL_ADJUST;
  1961. X                break;
  1962. X    
  1963. X      case DISPLAY_CENTRE:    if( actual_size <= frame_size )
  1964. X                { adjust_indent = (frame_size - actual_size)/2;
  1965. X                  padj = LAST_ADJUST;
  1966. X                }
  1967. X                else padj = ALL_ADJUST;
  1968. X                debug1(DGP,DD, "cdisp %s", EchoObject(null,x));
  1969. X                break;
  1970. X
  1971. X      case DISPLAY_RIGHT:    if( actual_size <= frame_size )
  1972. X                { adjust_indent = frame_size - actual_size;
  1973. X                  padj = LAST_ADJUST;
  1974. X                }
  1975. X                else padj = ALL_ADJUST;
  1976. X                debug1(DGP,DD, "rdisp %s", EchoObject(null,x));
  1977. X                break;
  1978. X    }
  1979. X
  1980. X    if( padj == ALL_ADJUST && adjustable_gaps > 0 && !bad_gap )
  1981. X    { adjust_inc = (frame_size - actual_size) / adjustable_gaps;
  1982. X      inc = max(adjust_inc, 0);
  1983. X    }
  1984. X    else adjust_inc = inc = 0;
  1985. X
  1986. X    debug2(DGP, DD, "ACAT %s %s",
  1987. X      EchoStyle(&save_style(x)), EchoObject(null, x));
  1988. X    debug3(DGP,DD,"frame_size = %s, actual_size = %s, adjustable_gaps = %d",
  1989. X      EchoLength(frame_size), EchoLength(actual_size), adjustable_gaps);
  1990. X    debug2(DGP,DD,"bad_gap = %s, adjust_inc = %s",
  1991. X      bool(bad_gap), EchoLength(adjust_inc));
  1992. X
  1993. X    /*********************************************************************/
  1994. X    /*                                                                   */
  1995. X    /*  The third and final step is to traverse x, fixing subobjects.    */
  1996. X    /*                                                                   */
  1997. X    /*********************************************************************/
  1998. X
  1999. X    FirstDefinite(x, link, y);
  2000. X    prev = y;
  2001. X    mk = xmk - back(x, dim) + back(y, dim) + adjust_indent;
  2002. X    NextDefiniteWithGap(x, link, y, g);
  2003. X    while( link != x )
  2004. X    {
  2005. X      /* fix previous definite now we know it isn't the last one  */
  2006. X      if( width(gap(g)) > 0 )
  2007. X      { FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim) + inc,
  2008. X          dim, adjust, NO_SUPPRESS, LAST_ADJUST, pg, count);
  2009. X        mk += save_actual_gap(g) + adjust_inc;
  2010. X      }
  2011. X      else
  2012. X      { FixAndPrintObject(prev, mk, back(prev, dim), fwd(prev, dim),
  2013. X          dim, adjust, NO_SUPPRESS, LAST_ADJUST, pg, count);
  2014. X        mk += save_actual_gap(g);
  2015. X      }
  2016. X
  2017. X      /* move on to next subobject */
  2018. X      prev = y;
  2019. X      NextDefiniteWithGap(x, link, y, g);
  2020. X    }
  2021. X
  2022. X    /* fix the last definite subobject, prev, which must exist */
  2023. X    FixAndPrintObject(prev, mk, back(prev, dim),
  2024. X      frame_size - (mk - xmk) - back(x, dim),
  2025. X      dim, adjust, NO_SUPPRESS, LAST_ADJUST, pg, count);
  2026. X      }
  2027. X      else for( link = Down(x);  link != x;  link = NextDown(link) )
  2028. X      {    Child(y, link);
  2029. X    if( !is_definite(type(y)) )  continue;
  2030. X    FixAndPrintObject(y, xmk, xb, xf, dim, adjust, NO_SUPPRESS,
  2031. X        padj,pg,count);
  2032. X      }
  2033. X      back(x, dim) = xb;  fwd(x, dim) = xf;
  2034. X      break;
  2035. X
  2036. X
  2037. X    case COL_THR:
  2038. X    case ROW_THR:
  2039. X
  2040. X      /* find and delete the count'th child y */
  2041. X      assert( (type(x) == COL_THR) == (dim == COL), "FixAndPrintObject: thr!" );
  2042. X      for( link = Down(x), uplink = Up(x), i = 1;
  2043. X    link != x && uplink != x && i < count;
  2044. X    link = NextDown(link), uplink = NextUp(uplink), i++ );
  2045. X      assert( link != x && uplink != x, "FixAndPrintObject: link or uplink!" );
  2046. X      CountChild(y, link, count);
  2047. X      MoveLink(uplink, link, CHILD);  DeleteLink(link);  /* IMPORTANT!!! */
  2048. X      assert( type(y) != GAP_OBJ, "FAPO: THR!");
  2049. X
  2050. X      /* assign size if not done previously */
  2051. X      if( thr_state(x) != FINALSIZE )
  2052. X      {    back(x, dim) = xb;  fwd(x, dim) = xf;
  2053. X    thr_state(x) = FINALSIZE;
  2054. X      }
  2055. X
  2056. X      /* *** else been here before, size is already decided; do nothing
  2057. X      {    if( back(x, dim) > xb || fwd(x, dim) > xf )
  2058. X    { Error(WARN, &fpos(y), "wrong %s chosen (sorry!)",
  2059. X        dim == COL ? "column width" : "row height");
  2060. X      if( back(x, dim) > xb )  back(x, dim) = xb;
  2061. X      if( fwd(x, dim)  > xf )  fwd(x, dim)  = xf;
  2062. X    }
  2063. X      }
  2064. X      *** */
  2065. X
  2066. X      /* fix y */
  2067. X      FixAndPrintObject(y, xmk, back(x, dim), fwd(x, dim), dim, LAST_ADJUST,
  2068. X    NO_SUPPRESS, padj, pg, count);
  2069. X      if( Up(x) == x )  Dispose(x);
  2070. X      break;
  2071. X
  2072. X
  2073. X    default:
  2074. X    
  2075. X      Error(INTERN, no_fpos, "FixAndPrint: found %s", Image(type(x)));
  2076. X      break;
  2077. X
  2078. X  } /* end switch */
  2079. X  debug2(DGP, D, "] FixAndPrintObject returning (size now %s,%s).",
  2080. X    EchoLength(back(x, dim)), EchoLength(fwd(x, dim)));
  2081. X} /* end FixAndPrintObject */
  2082. END_OF_FILE
  2083.   if test 28465 -ne `wc -c <'lout/z23.c'`; then
  2084.     echo shar: \"'lout/z23.c'\" unpacked with wrong size!
  2085.   fi
  2086.   # end of 'lout/z23.c'
  2087. fi
  2088. echo shar: End of archive 9 \(of 30\).
  2089. cp /dev/null ark9isdone
  2090. MISSING=""
  2091. 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
  2092.     if test ! -f ark${I}isdone ; then
  2093.     MISSING="${MISSING} ${I}"
  2094.     fi
  2095. done
  2096. if test "${MISSING}" = "" ; then
  2097.     echo You have unpacked all 30 archives.
  2098.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2099. else
  2100.     echo You still must unpack the following archives:
  2101.     echo "        " ${MISSING}
  2102. fi
  2103. exit 0
  2104. exit 0 # Just in case...
  2105.