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

  1. Newsgroups: comp.sources.misc
  2. From: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  3. Subject: v37i105:  lout - Lout document formatting system, v2, Part07/30
  4. Message-ID: <1993Jun1.051736.25469@sparky.imd.sterling.com>
  5. X-Md4-Signature: de533b7ce682aaab837348390588ad3e
  6. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Tue, 1 Jun 1993 05:17:36 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 105
  13. Archive-name: lout/part07
  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/doc/tr.eq/s2 lout/z03.c lout/z08.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 7 (of 30)."'
  25. if test -f 'lout/doc/tr.eq/s2' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'lout/doc/tr.eq/s2'\"
  27. else
  28.   echo shar: Extracting \"'lout/doc/tr.eq/s2'\" \(6731 characters\)
  29.   sed "s/^X//" >'lout/doc/tr.eq/s2' <<'END_OF_FILE'
  30. X@Section
  31. X   @Title { Symbols }
  32. X@Begin
  33. X@PP
  34. XEq prints characters in the fonts appropriate for mathematics:
  35. X@ID {
  36. X@Code "x - 2"
  37. X|7ct
  38. X@Eq { x-2 }
  39. X}
  40. XHere @Eq {x} is in Italic, @Eq { 2 } is in Roman, and @Eq { minus } is
  41. Xfrom the Symbol font.  The character @Code "-" is a @I symbol which
  42. Xstands for {@Eq {minus}}, and @Code "2" is also a symbol, standing for
  43. X{@Eq { 2 }}.  Eq includes a vast number of symbols:
  44. X@ID {
  45. X@Code "Omega delta int partial club"
  46. X|7ct
  47. X@Eq { Omega delta int partial club }
  48. X}
  49. XThe summary at the end of this report has the complete list.
  50. X@PP
  51. XSymbols whose names are made from letters should be separated from each
  52. Xother by at least one space or end of line, as was done above, or else
  53. XEq will become confused:
  54. X@ID {
  55. X@Code "Omegadelta"
  56. X|7ct
  57. X@Eq { Omegadelta }
  58. X}
  59. XSymbols whose names are made from digits and punctuation characters can,
  60. Xhowever, be run together with each other and with symbols made from
  61. Xletters:
  62. X@ID {
  63. X@Code "Omega-delta<=2"
  64. X|7ct
  65. X@Eq { Omega-delta<=2 }
  66. X}
  67. XThis rule applies throughout the Lout world.
  68. X@PP
  69. XSome symbols join objects together in mathematical ways:
  70. X@ID {
  71. X@Code "x sub 2"
  72. X|7ct
  73. X@Eq { x sub 2 }
  74. X}
  75. XHere the @Code "sub" symbol has taken the object just to its left, and
  76. Xthe object just to its right, and joined them into one object in the
  77. Xform of a subscript.  The two objects are called the left and right
  78. Xparameters of {@Code "sub"}, and they may be arbitrary Lout objects.
  79. X@PP
  80. XOther symbols of a similar kind include {@Code "sup"} for
  81. Xsuperscripting, @Code "over" for built-up fractions, and @Code "from"
  82. Xand @Code "to" for the lower and upper limits of sums, products,
  83. Xetc.  These symbols may be used together to produce complicated
  84. Xequations with astonishing ease:
  85. X@ID {
  86. X@Code {
  87. X"big sum from i=0 to n r sup i"
  88. X"= {r sup n+1 - 1} over r-1"
  89. X}
  90. X||7ct
  91. X@Eq { big sum from i=0 to n r sup i
  92. X= {r sup n+1 - 1} over r-1
  93. X}
  94. X}
  95. XHere @Code "sum" is just the @Eq { summation } symbol; @Code "from" and
  96. X@Code "to" do all the work of placing the limits.  They are quite
  97. Xindependent, so either or both may be omitted.  To get a superscript
  98. Xdirectly over a subscript, use the @Code "supp" and @Code "on" symbols:
  99. X@ID {
  100. X@Code "A supp 2 on 1"
  101. X|7ct
  102. X@Eq { A supp 2 on 1 }
  103. X}
  104. XThese two symbols should always be used together as shown.
  105. X@PP
  106. XAs usual in Lout, braces are used to group something into an indivisible
  107. Xobject.  Leaving them out creates ambiguities:
  108. X@ID @Code "a  sup  b  over  c"
  109. XThere are two possible interpretations for this:
  110. X@IndentedList
  111. X@LI {
  112. X@Code "{a  sup  b}  over  c"
  113. X|7ct
  114. X@Eq {  {a  sup  b}  over  c }
  115. X}
  116. X@LI {
  117. X@Code "a  sup  {b  over  c}"
  118. X|7ct
  119. X@Eq {  a  sup  {b  over  c} }
  120. X}
  121. X@EndList
  122. XEq chooses between them in the following way.  Every symbol that takes a
  123. Xparameter also has a {@I precedence}, which is a number.  For example,
  124. X@Code "sup" has precedence 60 and @Code "over" has precedence 54.  The
  125. Xsymbol with the highest precedence wins the object lying between them,
  126. Xso in the above case the first interpretation is chosen.  If two symbols
  127. Xof equal precedence compete for an object, the association is towards
  128. Xthe left:
  129. X@ID {
  130. X@Code "a sup b sub 2"
  131. X|7ct
  132. X@Eq { a sup b sub 2 }
  133. X}
  134. XIn this case it is more probable that the following right association
  135. Xwas actually wanted:
  136. X@ID {
  137. X@Code "a sup { b sub 2 }"
  138. X|7ct
  139. X@Eq { a sup { b sub 2 } }
  140. X}
  141. X@PP
  142. XWhite space between two objects is considered to be a symbol with
  143. Xprecedence 7, which is lower than the precedence of any Eq symbol; but
  144. Xif the two objects are immediately adjacent the precedence is 102, which
  145. Xis higher than the precedence of any Eq symbol.  Compare these three
  146. Xexamples:
  147. X@IL
  148. X@LI {
  149. X@Code "big sum from i=0 to n"
  150. X|7ct
  151. X@Eq {  big sum from i=0 to n }
  152. X}
  153. X@LI {
  154. X@Code "big sum from {i = 0} to n"
  155. X|7ct
  156. X@Eq {  big sum from {i = 0} to n }
  157. X}
  158. X@LI {
  159. X@Code "big sum from i = 0 to n"
  160. X|7ct
  161. X@Eq {  big sum from i = 0 to n }
  162. X}
  163. X@EL
  164. Xand you will see that some care is needed on this point.  Braces can
  165. Xalways be used to override precedence and associativity,
  166. Xand when in doubt the easiest course is to insert them.  Although
  167. XLout allows symbols to associate towards the left or right, Eq chooses
  168. Xto have only left associative symbols.  The summary at the end of this
  169. Xreport gives the precedence of every symbol.
  170. X@PP
  171. XThe @I matrix symbol {@PageMark matrix} builds an array of objects:
  172. X@ID {
  173. X@Code {
  174. X"matrix"
  175. X"   atleft { blpar }"
  176. X"   atright { brpar }"
  177. X"{ x sup 2 above x above 1"
  178. X"  nextcol"
  179. X"  y sup 2 above y above 1"
  180. X"  nextcol"
  181. X"  z sup 2 above z above 1"
  182. X"}"
  183. X}
  184. X||7ct
  185. X@Eq {
  186. Xmatrix
  187. X   atleft { blpar }
  188. X   atright { brpar }
  189. X{ x sup 2 above x above 1
  190. X  nextcol
  191. X  y sup 2 above y above 1
  192. X  nextcol
  193. X  z sup 2 above z above 1
  194. X}
  195. X}
  196. X}
  197. XThe @Code atleft and @Code atright options place vertically scaled
  198. Xversions of their
  199. Xvalues at each side; if either is omitted the value is taken to be an
  200. Xempty object of zero width by default.  The right parameter of @Code
  201. Xmatrix is the array itself.  It is a sequence of columns separated by
  202. X@Code nextcol symbols; each column is a sequence of objects separated by
  203. X@Code above symbols.
  204. X@PP
  205. XThe @Code nextcol and @Code above symbols have low precedence, but not
  206. Xas low as white space between two objects.  Therefore, unless the
  207. Xentries in the array are very simple, it is safest to enclose each of
  208. Xthem in braces.
  209. X@PP
  210. XColumns built with the @Code above symbol have their objects centred in
  211. Xthe column.  Also available are @Code labove for left-justified columns,
  212. X@Code cabove meaning the same as {@Code above}, @Code rabove for
  213. Xright-justified columns, and @Code mabove for alignment along column
  214. Xmarks.  Each column should contain only one kind of @Code above symbol
  215. X(although adventurous users might be able to get some mixtures to work), but
  216. Xdifferent columns may differ.  For example,
  217. X@ID @Code {
  218. X"@R \"Chain rule:\"  labove  @R \"Product rule:\""
  219. X"nextcol"
  220. X"{df over dx ^= df over dy cdot dy over dx}"
  221. X"mabove"
  222. X"{dfg over dy ^= f ` dg over dx + g df over dx}"
  223. X}
  224. Xhas result
  225. X@ID @Eq {
  226. X   @R "Chain rule:" labove @R "Product rule:"
  227. X   nextcol
  228. X   {df over dx ^= df over dy cdot dy over dx}
  229. X   mabove
  230. X   {dfg over dy ^= f ` dg over dx + g df over dx}
  231. X}
  232. XAs this last example shows, it is @Code nextcol and the various @Code
  233. Xabove symbols that lay out the array; @Code matrix attaches the @Code
  234. Xatleft and @Code atright options and makes sure the result appears in
  235. Xthe correct vertical position relative to the rest of the equation.  So
  236. Xthe right parameter of @Code matrix may be any object.
  237. X@PP
  238. XEach of the Eq symbols that takes parameters also has a @Code gap
  239. Xoption, which controls the amount of space inserted by the symbol:
  240. X@IL
  241. X@LI {
  242. X@Code "x over y"
  243. X|7ct
  244. X@Eq { x over y }
  245. X}
  246. X@LI {
  247. X6c @Wide @Code "x over gap { 3p } y"
  248. X|7ct
  249. X@Eq { x over gap { 3p } y }
  250. X}
  251. X@EL
  252. XEq usually gets the spacing right without help.
  253. X@End @Section
  254. END_OF_FILE
  255.   if test 6731 -ne `wc -c <'lout/doc/tr.eq/s2'`; then
  256.     echo shar: \"'lout/doc/tr.eq/s2'\" unpacked with wrong size!
  257.   fi
  258.   # end of 'lout/doc/tr.eq/s2'
  259. fi
  260. if test -f 'lout/z03.c' -a "${1}" != "-c" ; then 
  261.   echo shar: Will not clobber existing file \"'lout/z03.c'\"
  262. else
  263.   echo shar: Extracting \"'lout/z03.c'\" \(35079 characters\)
  264.   sed "s/^X//" >'lout/z03.c' <<'END_OF_FILE'
  265. X/*@z03.c:File Service:DefineFile(), FirstFile()@**************************** */
  266. X/*                                                                           */
  267. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  268. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  269. X/*                                                                           */
  270. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  271. X/*  Basser Department of Computer Science                                    */
  272. X/*  The University of Sydney 2006                                            */
  273. X/*  AUSTRALIA                                                                */
  274. X/*                                                                           */
  275. X/*  This program is free software; you can redistribute it and/or modify     */
  276. X/*  it under the terms of the GNU General Public License as published by     */
  277. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  278. X/*  any later version.                                                       */
  279. X/*                                                                           */
  280. X/*  This program is distributed in the hope that it will be useful,          */
  281. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  282. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  283. X/*  GNU General Public License for more details.                             */
  284. X/*                                                                           */
  285. X/*  You should have received a copy of the GNU General Public License        */
  286. X/*  along with this program; if not, write to the Free Software              */
  287. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  288. X/*                                                                           */
  289. X/*  FILE:         z03.c                                                      */
  290. X/*  MODULE:       File Service                                               */
  291. X/*  EXTERNS:      InitFiles(), AddToPath(), DefineFile(), FirstFile(),       */
  292. X/*                NextFile(), FileNum(), FileName(), EchoFilePos(),          */
  293. X/*                OpenFile(), ReadFromFile(), AppendToFile(), CloseFiles()   */
  294. X/*                                                                           */
  295. X/*****************************************************************************/
  296. X#include "externs"
  297. X#define MAX_TYPES      9            /* number of file types      */
  298. X#define MAX_PATHS      6            /* number of search paths    */
  299. X#define    TAB_MASK    0xFF            /* mask forces <= MAX_FILES  */
  300. X
  301. X#define    file_number(x)    word_font(x)        /* file number of file x     */
  302. X#define    updated(x)    broken(x)        /* TRUE when x is updated    */
  303. X#define    path(x)        back(x, COL)        /* search path for file x    */
  304. X
  305. Xstatic    int    file_count;            /* total number of files     */
  306. Xstatic    OBJECT    fvec[MAX_FILES] = { nil };    /* the file table            */
  307. Xstatic    OBJECT    file_list[MAX_TYPES];        /* files of each type        */
  308. Xstatic    OBJECT    file_path[MAX_PATHS];        /* the search paths          */
  309. X#ifdef DEBUG_ON
  310. Xstatic    char    *file_types[]        /* the type names for debug  */
  311. X        = { "source", "include", "incgraphic", "database",
  312. X            "index", "font", "prepend", "hyph", "hyphpacked" };
  313. X#endif
  314. X
  315. X
  316. X/*****************************************************************************/
  317. X/*                                                                           */
  318. X/*  no_fpos                                                                  */
  319. X/*                                                                           */
  320. X/*  A null file position value.                                              */
  321. X/*                                                                           */
  322. X/*****************************************************************************/
  323. X
  324. Xstatic FILE_POS no_file_pos = {0, 0, 0};
  325. XFILE_POS *no_fpos = &no_file_pos;
  326. X
  327. X
  328. X/*****************************************************************************/
  329. X/*                                                                           */
  330. X/*  #define hash(str, val)                                                   */
  331. X/*                                                                           */
  332. X/*  Hash the string str and return its value in val.                         */
  333. X/*                                                                           */
  334. X/*****************************************************************************/
  335. X
  336. X#define hash(str, val)                            \
  337. X{ p = str;                                \
  338. X  val = *p++;                                \
  339. X  while( *p ) val += *p++;                        \
  340. X  val = (val * 8) & TAB_MASK;                        \
  341. X}
  342. X
  343. X
  344. X/*****************************************************************************/
  345. X/*                                                                           */
  346. X/*  InitFiles()                                                              */
  347. X/*                                                                           */
  348. X/*  Initialize this module.                                                  */
  349. X/*                                                                           */
  350. X/*****************************************************************************/
  351. X
  352. XInitFiles()
  353. X{ int i;
  354. X  for( i = 0;  i < MAX_TYPES; i++ )  file_list[i]  = New(ACAT);
  355. X  for( i = 0;  i < MAX_PATHS; i++ )  file_path[i] = New(ACAT);
  356. X  fvec[0] = file_list[0];    /* so that no files will be given slot 0 */
  357. X  file_count = 1;
  358. X} /* end InitFiles */
  359. X
  360. X
  361. X/*@@**************************************************************************/
  362. X/*                                                                           */
  363. X/*  AddToPath(fpath, dirname)                                                */
  364. X/*                                                                           */
  365. X/*  Add the directory dirname to the end of search path fpath.               */
  366. X/*                                                                           */
  367. X/*****************************************************************************/
  368. X
  369. XAddToPath(fpath, dirname)
  370. Xint fpath; unsigned char *dirname;
  371. X{ OBJECT x;
  372. X  x = MakeWord(dirname, no_fpos);
  373. X  Link(file_path[fpath], x);
  374. X} /* end AddToPath */
  375. X
  376. X
  377. X/*****************************************************************************/
  378. X/*                                                                           */
  379. X/*  FILE_NUM DefineFile(x, ftype, fpath)                                     */
  380. X/*                                                                           */
  381. X/*  Declare file x, which is a WORD object containing the file name.         */
  382. X/*  ftype is the file's type; fpath is its search path.                      */
  383. X/*                                                                           */
  384. X/*****************************************************************************/
  385. X
  386. XFILE_NUM DefineFile(x, ftype, fpath)
  387. XOBJECT x;  int ftype, fpath;
  388. X{ register unsigned char *p;
  389. X  register int i;
  390. X  assert( type(x) == WORD, "DefineFile: type(x) != WORD!" );
  391. X  assert( ftype < MAX_TYPES, "DefineFile: ftype!" );
  392. X  debug3(DFS, D, "DefineFile( %s, %s, %d )",
  393. X    EchoObject(null,x), file_types[ftype], fpath);
  394. X  if( ftype == SOURCE_FILE && (i = strlen(string(x))) >= 3 )
  395. X  {
  396. X    /* check that file name does not end in ".li" or ".ld" */
  397. X    if( strcmp(&string(x)[i-strlen(DATA_SUFFIX)], DATA_SUFFIX) == 0 )
  398. X      Error(FATAL, &fpos(x),
  399. X    "database file %s where source file expected", string(x));
  400. X    if( strcmp(&string(x)[i-strlen(INDEX_SUFFIX)], INDEX_SUFFIX) == 0 )
  401. X      Error(FATAL, &fpos(x),
  402. X    "database index file %s where source file expected", string(x));
  403. X  }
  404. X  if( ++file_count >= MAX_FILES ) Error(FATAL, &fpos(x), "too many file names");
  405. X  hash(string(x), i);
  406. X  while( fvec[i] != nil )
  407. X    if( ++i >= MAX_FILES ) i = 0;
  408. X  fvec[i] = x;
  409. X  Link(file_list[ftype], x);
  410. X  file_number(x) = i;
  411. X  path(x) = fpath;
  412. X  debug1(DFS, D, "DefineFile returning %s",
  413. X    i == NO_FILE ? (unsigned char *) "none" : FileName( (FILE_NUM) i));
  414. X  return (FILE_NUM) i;
  415. X} /* end DefineFile */
  416. X
  417. X
  418. X/*****************************************************************************/
  419. X/*                                                                           */
  420. X/*  FILE_NUM FirstFile(ftype)                                                */
  421. X/*                                                                           */
  422. X/*  Returns first file of type ftype, else NO_FILE.                          */
  423. X/*                                                                           */
  424. X/*****************************************************************************/
  425. X
  426. XFILE_NUM FirstFile(ftype)
  427. Xint ftype;
  428. X{ FILE_NUM i;
  429. X  OBJECT link, y;
  430. X  debug1(DFS, D, "FirstFile( %s )", file_types[ftype]);
  431. X  link = Down(file_list[ftype]);
  432. X  if( type(link) == ACAT )  i = NO_FILE;
  433. X  else
  434. X  { Child(y, link);
  435. X    i = file_number(y);
  436. X  }
  437. X  debug1(DFS, D, "FirstFile returning %s",
  438. X    i == NO_FILE ? (unsigned char *) "none" : FileName(i));
  439. X  return i;
  440. X} /* end FirstFile */
  441. X
  442. X
  443. X/*@@**************************************************************************/
  444. X/*                                                                           */
  445. X/*  FILE_NUM NextFile(i)                                                     */
  446. X/*                                                                           */
  447. X/*  Returns the next file after file i of i's type, else NO_FILE.            */
  448. X/*                                                                           */
  449. X/*****************************************************************************/
  450. X
  451. XFILE_NUM NextFile(i)
  452. XFILE_NUM i;
  453. X{ OBJECT link, y;
  454. X  debug1(DFS, D, "NextFile( %s )", EchoObject(null, fvec[i]));
  455. X  link = NextDown(Up(fvec[i]));
  456. X  if( type(link) == ACAT )  i = NO_FILE;
  457. X  else
  458. X  { Child(y, link);
  459. X    i = file_number(y);
  460. X  }
  461. X  debug1(DFS, D, "NextFile returning %s",
  462. X    i == NO_FILE ? (unsigned char *) "none" : FileName(i));
  463. X  return i;
  464. X} /* end NextFile */
  465. X
  466. X
  467. X/*****************************************************************************/
  468. X/*                                                                           */
  469. X/*  FILE_NUM FileNum(str)                                                    */
  470. X/*                                                                           */
  471. X/*  Return the file number of the file with name str, else NO_FILE.          */
  472. X/*                                                                           */
  473. X/*****************************************************************************/
  474. X
  475. XFILE_NUM FileNum(str)
  476. Xunsigned char *str;
  477. X{ register unsigned char *p;
  478. X  register int i;
  479. X  debug1(DFS, D, "FileNum( %s )", str);
  480. X  hash(str, i);
  481. X  while( fvec[i] != nil && strcmp(string(fvec[i]), str) != 0 )
  482. X    if( ++i >= MAX_FILES ) i = 0;
  483. X  if( fvec[i] == nil ) i = 0;
  484. X  debug1(DFS, D, "FileNum returning %s",
  485. X    i == NO_FILE ? (unsigned char *) "none" : FileName( (FILE_NUM) i));
  486. X  return (FILE_NUM) i;
  487. X} /* end FileNum */
  488. X
  489. X
  490. X/*****************************************************************************/
  491. X/*                                                                           */
  492. X/*  unsigned char *FileName(fnum)                                            */
  493. X/*                                                                           */
  494. X/*  Return the string name of the file with this number.  This is the name   */
  495. X/*  provided by DefineFile until OpenFile is called, after which it is the   */
  496. X/*  full path name.                                                          */
  497. X/*                                                                           */
  498. X/*****************************************************************************/
  499. X
  500. Xunsigned char *FileName(fnum)
  501. XFILE_NUM fnum;
  502. X{ OBJECT x;
  503. X  assert( fnum > 0 , "FileName: num!" );
  504. X  assert( fvec[fnum] != nil, "FileName: fvec[fnum] == nil!" );
  505. X  x = fvec[fnum];
  506. X  if( Down(x) != x )  Child(x, Down(x));
  507. X  return string(x);
  508. X} /* end FileName */
  509. X
  510. X
  511. X/*@@**************************************************************************/
  512. X/*                                                                           */
  513. X/*  unsigned char *EchoFilePos(pos)                                          */
  514. X/*                                                                           */
  515. X/*  Returns a string reporting the value of file position pos.               */
  516. X/*                                                                           */
  517. X/*****************************************************************************/
  518. X
  519. Xstatic unsigned char buff[2][MAX_LINE];  static bp = 1;
  520. X
  521. Xstatic append_fpos(pos)
  522. XFILE_POS *pos;
  523. X{ OBJECT x;
  524. X  x = fvec[file_num(*pos)];
  525. X  assert( x != nil, "EchoFilePos: fvec[] entry is nil!" );
  526. X  if( file_num(fpos(x)) > 0 )
  527. X  { append_fpos( &fpos(x) );
  528. X    if( strlen(buff[bp]) + 2 >= MAX_LINE )
  529. X      Error(FATAL,no_fpos,"file position %s... is too long to print", buff[bp]);
  530. X    strcat(buff[bp], " /");
  531. X  }
  532. X  if( strlen(buff[bp]) + strlen(string(x)) + 13 >= MAX_LINE )
  533. X    Error(FATAL, no_fpos, "file position %s... is too long to print", buff[bp]);
  534. X  sprintf(&buff[bp][strlen(buff[bp])], " \"%s\"", string(x));
  535. X  if( line_num(*pos) != 0 )
  536. X    sprintf(&buff[bp][strlen(buff[bp])]," %d,%d",line_num(*pos), col_num(*pos));
  537. X} /* end append_fpos */
  538. X
  539. Xunsigned char *EchoFilePos(pos)
  540. XFILE_POS *pos;
  541. X{ bp = (bp + 1) % 2;
  542. X  strcpy(buff[bp], "");
  543. X  if( file_num(*pos) > 0 )  append_fpos(pos);
  544. X  return buff[bp];
  545. X} /* end EchoFilePos */
  546. X
  547. X
  548. X/*****************************************************************************/
  549. X/*                                                                           */
  550. X/*  FILE_POS *PosOfFile(fnum)                                                */
  551. X/*                                                                           */
  552. X/*  Returns a pointer to the file position where file fnum was encountered.  */
  553. X/*                                                                           */
  554. X/*****************************************************************************/
  555. X
  556. XFILE_POS *PosOfFile(fnum)
  557. XFILE_NUM fnum;
  558. X{ OBJECT x;
  559. X  x = fvec[fnum];
  560. X  assert( x != nil, "PosOfFile: fvec[] entry is nil!" );
  561. X  return &fpos(x);
  562. X}
  563. X
  564. X
  565. X/*****************************************************************************/
  566. X/*                                                                           */
  567. X/*  FILE *SearchPath(str, fpath, check_ld, full_name, xfpos)                 */
  568. X/*                                                                           */
  569. X/*  Search the given path for a file whose name is str.  If found, open      */
  570. X/*  it; return the resulting FILE *.                                         */
  571. X/*                                                                           */
  572. X/*  If check_ld is TRUE, it means that the file to be opened is a .li file   */
  573. X/*  and OpenFile() is required to check whether the corresponding .ld file   */
  574. X/*  is present.  If it is, then the search must stop.                        */
  575. X/*                                                                           */
  576. X/*  Also return the full path name in object *full_name if reqd, else nil.   */
  577. X/*                                                                           */
  578. X/*****************************************************************************/
  579. X
  580. Xstatic FILE *SearchPath(str, fpath, check_ld, full_name, xfpos)
  581. Xunsigned char *str;  OBJECT fpath;  BOOLEAN check_ld;
  582. XOBJECT *full_name;  FILE_POS *xfpos;
  583. X{ 
  584. X  unsigned char buff[MAX_LINE];  OBJECT link, y;  FILE *fp;
  585. X  debug3(DFS, DD, "SearchPath(%s, %s, %s, -)", str, EchoObject(null, fpath),
  586. X    bool(check_ld));
  587. X  *full_name = nil;
  588. X  if( strcmp(str, "-") == 0 )
  589. X  { fp = stdin;
  590. X    debug0(DFS, DD, "  opened stdin");
  591. X  }
  592. X  else if( str[0] == '/' )
  593. X  { fp = fopen(str, "r");
  594. X    debug1(DFS, DD, fp==null ? "  failed on %s" : "  succeeded on %s", str);
  595. X  }
  596. X  else
  597. X  { fp = null;
  598. X    for( link = Down(fpath);  fp==null && link != fpath; link = NextDown(link) )
  599. X    { Child(y, link);
  600. X      if( string(y)[0] == '\0' )
  601. X      { strcpy(buff, str);
  602. X    fp = fopen(str, "r");
  603. X    debug1(DFS, DD, fp==null ? "  failed on %s" : "  succeeded on %s", str);
  604. X      }
  605. X      else
  606. X      {    if( strlen(string(y)) + 1 + strlen(str) >= MAX_LINE )
  607. X      Error(FATAL, &fpos(y), "file path name %s/%s is too long",
  608. X        string(y), str);
  609. X    sprintf(buff, "%s/%s", string(y), str);
  610. X    fp = fopen(buff, "r");
  611. X    debug1(DFS, DD, fp==null ? "  failed on %s" : "  succeeded on %s",buff);
  612. X    if( fp != null ) *full_name = MakeWord(buff, xfpos);
  613. X      }
  614. X      if( fp == null && check_ld )
  615. X      {    strcpy(&buff[strlen(buff) - strlen(INDEX_SUFFIX)], DATA_SUFFIX);
  616. X    fp = fopen(buff, "r");
  617. X    debug1(DFS,DD,fp==null ? "  failed on %s" : "  succeeded on %s", buff);
  618. X    if( fp != null )
  619. X    { fclose(fp);
  620. X      debug0(DFS, D, "SearchPath returning null (adjacent .ld file)");
  621. X      return null;
  622. X    }
  623. X      }
  624. X    }
  625. X  }
  626. X  debug1(DFS, DD, "SearchPath returning (fp %s null)", fp==null ? "==" : "!=");
  627. X  return fp;
  628. X} /* end SearchPath */
  629. X
  630. X
  631. X/*****************************************************************************/
  632. X/*                                                                           */
  633. X/*  FILE *OpenFile(fnum, check_ld)                                           */
  634. X/*                                                                           */
  635. X/*  Open for reading the file whose number is fnum.  This involves           */
  636. X/*  searching for it along its path if not previously opened.                */
  637. X/*                                                                           */
  638. X/*  If check_ld is TRUE, it means that the file to be opened is a .li file   */
  639. X/*  and OpenFile() is required to check whether the corresponding .ld file   */
  640. X/*  is present.  If it is, then the search must stop.                        */
  641. X/*                                                                           */
  642. X/*****************************************************************************/
  643. X
  644. XFILE *OpenFile(fnum, check_ld)
  645. XFILE_NUM fnum;  BOOLEAN check_ld;
  646. X{ FILE *fp;  OBJECT full_name, y;
  647. X  ifdebug(DPP, D, ProfileOn("OpenFile"));
  648. X  debug2(DFS, D, "OpenFile(%s, %s)", FileName(fnum), bool(check_ld));
  649. X  if( Down(fvec[fnum]) != fvec[fnum] )
  650. X  { Child(y, Down(fvec[fnum]));
  651. X    fp = fopen(string(y), "r");
  652. X    debug1(DFS,DD,fp==null ? "  failed on %s" : "  succeeded on %s", string(y));
  653. X  }
  654. X  else
  655. X  { fp = SearchPath(string(fvec[fnum]), file_path[path(fvec[fnum])],
  656. X        check_ld, &full_name, &fpos(fvec[fnum]));
  657. X    if( full_name != nil )  Link(fvec[fnum], full_name);
  658. X  }
  659. X  ifdebug(DPP, D, ProfileOff("OpenFile"));
  660. X  debug1(DFS, D, "OpenFile returning (fp %s null)", fp==null ? "==" : "!=");
  661. X  return fp;
  662. X} /* end OpenFile */
  663. X
  664. X
  665. X/*****************************************************************************/
  666. X/*                                                                           */
  667. X/*  FILE *OpenIncGraphicFile(str, typ, full_name, xfpos)                     */
  668. X/*                                                                           */
  669. X/*  Open for reading the @IncludeGraphic file str; typ is INCGRAPHIC or      */
  670. X/*  SINCGRAPHIC.  Return the full name in full_name.                         */
  671. X/*                                                                           */
  672. X/*****************************************************************************/
  673. X
  674. XFILE *OpenIncGraphicFile(str, typ, full_name, xfpos)
  675. Xunsigned char *str;  unsigned char typ;  OBJECT *full_name;  FILE_POS *xfpos;
  676. X{ FILE *fp;  int p;
  677. X  debug2(DFS, D, "OpenIncGraphicFile(%s, %s, -)", str, Image(typ));
  678. X  assert( typ == INCGRAPHIC || typ == SINCGRAPHIC, "OpenIncGraphicFile!" );
  679. X  p = (typ == INCGRAPHIC ? INCLUDE_PATH : SYSINCLUDE_PATH);
  680. X  fp = SearchPath(str, file_path[p], FALSE, full_name, xfpos);
  681. X  if( *full_name == nil )  *full_name = MakeWord(str, xfpos);
  682. X  debug2(DFS, D, "OpenIncGraphicFile returning (fp %s null, *full_name = %s)",
  683. X    fp==null ? "==" : "!=", string(*full_name));
  684. X  return fp;
  685. X} /* end OpenIncGraphicFile */
  686. X
  687. X
  688. X/*@@**************************************************************************/
  689. X/*                                                                           */
  690. X/*  OBJECT ReadFromFile(fnum, pos, sym)                                      */
  691. X/*                                                                           */
  692. X/*  Read an object from file fnum starting at position pos.                  */
  693. X/*  The object may include @Env operators defining its environment.          */
  694. X/*  If sym != nil, sym is the symbol which is to be read in.                 */
  695. X/*                                                                           */
  696. X/*****************************************************************************/
  697. X
  698. XOBJECT ReadFromFile(fnum, pos, sym)
  699. XFILE_NUM fnum; long pos;  OBJECT sym;
  700. X{ OBJECT t, res; int ipos;
  701. X  ifdebug(DPP, D, ProfileOn("ReadFromFile"));
  702. X  ifdebug(DFS, D, ipos = (int) pos);
  703. X  debug3(DFS, D, "ReadFromFile(%s, %d, %s)", FileName(fnum), ipos,SymName(sym));
  704. X  LexPush(fnum, (int) pos, DATABASE_FILE);
  705. X  SwitchScope(sym);
  706. X  t = LexGetToken();
  707. X  if( type(t) != LBR )
  708. X  { debug1(DFS, D, "  following because type(t) = %s", Image(type(t)));
  709. X    Error(FATAL, &fpos(t),"syntax error (missing %s) in database file", KW_LBR);
  710. X  }
  711. X  res = Parse(&t, StartSym, FALSE, FALSE);
  712. X  if( t != nil || type(res) != CLOSURE )
  713. X  { debug1(DFS, D, "  following because of %s", t != nil ? "t" : "type(res)");
  714. X    Error(FATAL, &fpos(res), "syntax error in database file");
  715. X  }
  716. X  UnSwitchScope(sym);
  717. X  LexPop();
  718. X  debug1(DFS, D, "ReadFromFile returning %s", EchoObject(null, res));
  719. X  ifdebug(DPP, D, ProfileOff("ReadFromFile"));
  720. X  return res;
  721. X} /* end ReadFromFile */
  722. X
  723. X
  724. Xstatic FILE_NUM    last_write_fnum = NO_FILE;
  725. Xstatic FILE    *last_write_fp  = null;
  726. X
  727. X
  728. X/*****************************************************************************/
  729. X/*                                                                           */
  730. X/*  static WriteClosure(x)                                                   */
  731. X/*                                                                           */
  732. X/*  Write closure x to file last_write_fp, without enclosing braces and      */
  733. X/*  without any environment attached.                                        */
  734. X/*                                                                           */
  735. X/*****************************************************************************/
  736. X
  737. Xstatic BOOLEAN need_lvis(sym)        /* true if @LVis needed before sym */
  738. XOBJECT sym;
  739. X{ return !visible(sym) &&
  740. X     enclosing(sym) != StartSym &&
  741. X     type(enclosing(sym)) == LOCAL;
  742. X} /* end need_lvis */
  743. X
  744. Xstatic WriteClosure(x)
  745. XOBJECT x;
  746. X{ OBJECT y, link, z, sym;
  747. X  BOOLEAN npar_seen, name_printed;
  748. X  static WriteObject();
  749. X
  750. X  sym = actual(x);  npar_seen = FALSE;  name_printed = FALSE;
  751. X  for( link = Down(x);  link != x;  link = NextDown(link) )
  752. X  { Child(y, link);
  753. X    if( type(y) == PAR )  switch( type(actual(y)) )
  754. X    {
  755. X      case LPAR:
  756. X      
  757. X    assert( Down(y) != y, "WriteObject/CLOSURE: LPAR!" );
  758. X    Child(z, Down(y));
  759. X    WriteObject(z, (int) precedence(sym));
  760. X    fputs(" ", last_write_fp);
  761. X    break;
  762. X
  763. X
  764. X      case NPAR:
  765. X      
  766. X    assert( Down(y) != y, "WriteObject/CLOSURE: NPAR!" );
  767. X    Child(z, Down(y));
  768. X    if( !name_printed )
  769. X    { if( need_lvis(sym) )
  770. X      { fputs(KW_LVIS, last_write_fp);
  771. X        fputs(" ", last_write_fp);
  772. X      }
  773. X      fputs(SymName(sym), last_write_fp);
  774. X      name_printed = TRUE;
  775. X    }
  776. X    fputs("\n   ", last_write_fp);
  777. X    fputs(SymName(actual(y)), last_write_fp);
  778. X    fprintf(last_write_fp, " %s ", KW_LBR);
  779. X    WriteObject(z, NO_PREC);
  780. X    fprintf(last_write_fp, " %s", KW_RBR);
  781. X    npar_seen = TRUE;
  782. X    break;
  783. X
  784. X
  785. X      case RPAR:
  786. X      
  787. X    assert( Down(y) != y, "WriteObject/CLOSURE: RPAR!" );
  788. X    Child(z, Down(y));
  789. X    if( !name_printed )
  790. X    { if( need_lvis(sym) )
  791. X      { fputs(KW_LVIS, last_write_fp);
  792. X        fputs(" ", last_write_fp);
  793. X      }
  794. X      fputs(SymName(sym), last_write_fp);
  795. X      name_printed = TRUE;
  796. X    }
  797. X    fputs(npar_seen ? "\n" : " ", last_write_fp);
  798. X    if( has_body(sym) )
  799. X    { fputs(KW_LBR, last_write_fp);
  800. X      fputs(" ", last_write_fp);
  801. X      WriteObject(z, NO_PREC);
  802. X      fputs(" ", last_write_fp);
  803. X      fputs(KW_RBR, last_write_fp);
  804. X    }
  805. X    else WriteObject(z, (int) precedence(sym));
  806. X    break;
  807. X
  808. X
  809. X      default:
  810. X      
  811. X    Error(INTERN, &fpos(y), "WriteClosure: %s", Image(type(actual(y))) );
  812. X    break;
  813. X
  814. X    } /* end switch */
  815. X  } /* end for each parameter */
  816. X  if( !name_printed )
  817. X  { if( need_lvis(sym) )
  818. X    { fputs(KW_LVIS, last_write_fp);
  819. X      fputs(" ", last_write_fp);
  820. X    }
  821. X    fputs(SymName(sym), last_write_fp);
  822. X    name_printed = TRUE;
  823. X  }
  824. X} /* end WriteClosure */
  825. X
  826. X/*****************************************************************************/
  827. X/*                                                                           */
  828. X/*  static WriteObject(x, outer_prec)                                        */
  829. X/*                                                                           */
  830. X/*  Write object x to file last_write_fp, assuming it is a subobject of an   */
  831. X/*  object and the precedence of operators enclosing it is outer_prec.       */
  832. X/*                                                                           */
  833. X/*****************************************************************************/
  834. X
  835. Xstatic WriteObject(x, outer_prec)
  836. XOBJECT x;  int outer_prec;
  837. X{ OBJECT link, y, gap_obj, sym, env;  unsigned char *name;
  838. X  int prec, i, last_prec;  BOOLEAN braces_needed;
  839. X  switch( type(x) )
  840. X  {
  841. X
  842. X    case WORD:
  843. X
  844. X      if( strlen(string(x)) == 0 && outer_prec > ACAT_PREC )
  845. X      {    fputs(KW_LBR, last_write_fp);
  846. X    fputs(KW_RBR, last_write_fp);
  847. X      }
  848. X      else fputs(string(x), last_write_fp);
  849. X      break;
  850. X
  851. X    
  852. X    case VCAT:  prec = VCAT_PREC;  goto ETC;
  853. X    case HCAT:  prec = HCAT_PREC;  goto ETC;
  854. X    case ACAT:  prec = ACAT_PREC;  goto ETC;
  855. X
  856. X      ETC:
  857. X      if( prec < outer_prec )  fputs(KW_LBR, last_write_fp);
  858. X      last_prec = prec;
  859. X      for( link = Down(x);  link != x;  link = NextDown(link) )
  860. X      {    Child(y, link);
  861. X    if( type(y) == GAP_OBJ )
  862. X    { if( Down(y) == y )
  863. X      { assert( type(x) == ACAT, "WriteObject: Down(y) == y!" );
  864. X        for( i = 1;  i <= vspace(y);  i++ )  fputs("\n", last_write_fp);
  865. X        for( i = 1;  i <= hspace(y);  i++ )  fputs(" ",  last_write_fp);
  866. X        last_prec = (vspace(y) + hspace(y) == 0) ? JUXTA_PREC : ACAT_PREC;
  867. X      }
  868. X      else
  869. X      { Child(gap_obj, Down(y));
  870. X        fprintf(last_write_fp, type(x) == ACAT ? " %s" : "\n%s",
  871. X        EchoCatOp( (unsigned) type(x), mark(gap(y)), join(gap(y))));
  872. X        if( type(gap_obj) != WORD || strlen(string(gap_obj)) != 0 )
  873. X        WriteObject(gap_obj, FORCE_PREC);
  874. X        fputs(" ", last_write_fp);
  875. X        last_prec = prec;
  876. X      }
  877. X    }
  878. X    else
  879. X    { if( type(x) == ACAT )
  880. X      { OBJECT next_gap;  int next_prec;
  881. X        if( NextDown(link) != x )
  882. X        { Child(next_gap, NextDown(link));
  883. X          assert( type(next_gap) == GAP_OBJ, "WriteObject: next_gap!" );
  884. X          next_prec = (vspace(next_gap) + hspace(next_gap) == 0)
  885. X                ? JUXTA_PREC : ACAT_PREC;
  886. X        }
  887. X        else next_prec = prec;
  888. X        WriteObject(y, max(last_prec, next_prec));
  889. X      }
  890. X      else WriteObject(y, prec);
  891. X    }
  892. X      }
  893. X      if( prec < outer_prec )  fputs(KW_RBR, last_write_fp);
  894. X      break;
  895. X
  896. X
  897. X    case ENV:
  898. X
  899. X      if( Down(x) == x )
  900. X      { /* do nothing */
  901. X      }
  902. X      else if( Down(x) == LastDown(x) )
  903. X      {    Child(y, Down(x));
  904. X    assert( type(y) == CLOSURE, "WriteObject: ENV/CLOSURE!" );
  905. X    assert( LastDown(y) != y, "WriteObject: ENV/LastDown(y)!" );
  906. X    Child(env, LastDown(y));
  907. X    assert( type(env) == ENV, "WriteObject: ENV/env!" );
  908. X    WriteObject(env, NO_PREC);
  909. X    fputs(KW_LBR, last_write_fp);
  910. X    WriteClosure(y);
  911. X    fputs(KW_RBR, last_write_fp);
  912. X    fputs("\n",   last_write_fp);
  913. X      }
  914. X      else
  915. X      {    Child(env, LastDown(x));
  916. X    assert( type(env) == ENV, "WriteObject: ENV/ENV!" );
  917. X    WriteObject(env, NO_PREC);
  918. X    Child(y, Down(x));
  919. X    assert( type(y) == CLOSURE, "WriteObject: ENV/ENV+CLOSURE!" );
  920. X    WriteObject(y, NO_PREC);
  921. X      }
  922. X      break;
  923. X
  924. X
  925. X    case CLOSURE:
  926. X
  927. X      sym = actual(x);  env = nil;
  928. X      if( LastDown(x) != x )
  929. X      {    Child(y, LastDown(x));
  930. X    if( type(y) == ENV )  env = y;
  931. X      }
  932. X
  933. X      braces_needed = env != nil ||
  934. X    (precedence(sym) <= outer_prec && (has_lpar(sym) || has_rpar(sym)));
  935. X
  936. X      /* print environment */
  937. X      if( env != nil )
  938. X      {    fputs(KW_ENV, last_write_fp);
  939. X          fputs("\n", last_write_fp);
  940. X    WriteObject(env, NO_PREC);
  941. X      }
  942. X
  943. X      /* print left brace if needed */
  944. X      if( braces_needed )  fputs(KW_LBR, last_write_fp);
  945. X    
  946. X      /* print the closure proper */
  947. X      WriteClosure(x);
  948. X
  949. X      /* print closing brace if needed */
  950. X      if( braces_needed )  fputs(KW_RBR, last_write_fp);
  951. X
  952. X      /* print closing environment if needed */
  953. X      if( env != nil )
  954. X      { fputs("\n", last_write_fp);
  955. X    fputs(KW_CLOS, last_write_fp);
  956. X          fputs("\n", last_write_fp);
  957. X      }
  958. X      break;
  959. X
  960. X
  961. X    case CROSS:
  962. X
  963. X      Child(y, Down(x));
  964. X      assert( type(y) == CLOSURE, "WriteObject/CROSS: type(y) != CLOSURE!" );
  965. X      fputs(SymName(actual(y)), last_write_fp);
  966. X      fputs(KW_CROSS, last_write_fp);
  967. X      Child(y, LastDown(x));
  968. X      WriteObject(y, FORCE_PREC);
  969. X      break;
  970. X
  971. X
  972. X    case NULL_CLOS:    name = (unsigned char *) KW_NULL;    goto SETC;
  973. X    case ONE_COL:    name = (unsigned char *) KW_ONE_COL;    goto SETC;
  974. X    case ONE_ROW:    name = (unsigned char *) KW_ONE_ROW;    goto SETC;
  975. X    case WIDE:        name = (unsigned char *) KW_WIDE;    goto SETC;
  976. X    case HIGH:        name = (unsigned char *) KW_HIGH;    goto SETC;
  977. X    case HSCALE:    name = (unsigned char *) KW_HSCALE;    goto SETC;
  978. X    case VSCALE:    name = (unsigned char *) KW_VSCALE;    goto SETC;
  979. X    case SCALE:        name = (unsigned char *) KW_SCALE;    goto SETC;
  980. X    case HCONTRACT:    name = (unsigned char *) KW_HCONTRACT;    goto SETC;
  981. X    case VCONTRACT:    name = (unsigned char *) KW_VCONTRACT;    goto SETC;
  982. X    case HEXPAND:    name = (unsigned char *) KW_HEXPAND;    goto SETC;
  983. X    case VEXPAND:    name = (unsigned char *) KW_VEXPAND;    goto SETC;
  984. X    case PADJUST:    name = (unsigned char *) KW_PADJUST;    goto SETC;
  985. X    case HADJUST:    name = (unsigned char *) KW_HADJUST;    goto SETC;
  986. X    case VADJUST:    name = (unsigned char *) KW_VADJUST;    goto SETC;
  987. X    case ROTATE:    name = (unsigned char *) KW_ROTATE;    goto SETC;
  988. X    case CASE:        name = (unsigned char *) KW_CASE;    goto SETC;
  989. X    case YIELD:        name = (unsigned char *) KW_YIELD;    goto SETC;
  990. X    case FONT:        name = (unsigned char *) KW_FONT;    goto SETC;
  991. X    case SPACE:        name = (unsigned char *) KW_SPACE;    goto SETC;
  992. X    case BREAK:        name = (unsigned char *) KW_BREAK;    goto SETC;
  993. X    case NEXT:        name = (unsigned char *) KW_NEXT;    goto SETC;
  994. X    case OPEN:        name = (unsigned char *) KW_OPEN;    goto SETC;
  995. X    case TAGGED:    name = (unsigned char *) KW_TAGGED;    goto SETC;
  996. X    case INCGRAPHIC:    name = (unsigned char *) KW_INCGRAPHIC;    goto SETC;
  997. X    case SINCGRAPHIC:    name = (unsigned char *) KW_SINCGRAPHIC;goto SETC;
  998. X    case GRAPHIC:    name = (unsigned char *) KW_GRAPHIC;    goto SETC;
  999. X
  1000. X      /* print left parameter, if present */
  1001. X      SETC:
  1002. X      if( DEFAULT_PREC <= outer_prec )  fputs(KW_LBR, last_write_fp);
  1003. X      if( Down(x) != LastDown(x) )
  1004. X      {    Child(y, Down(x));
  1005. X    WriteObject(y, DEFAULT_PREC);
  1006. X    fputs(" ", last_write_fp);
  1007. X      }
  1008. X
  1009. X      /* print the symbol's name */
  1010. X      fputs(name, last_write_fp);
  1011. X
  1012. X      /* print right parameter, if present */
  1013. X      if( LastDown(x) != x )
  1014. X      {    Child(y, LastDown(x));
  1015. X    fputs(" ", last_write_fp);
  1016. X    if( type(x) == OPEN )
  1017. X    { fputs(KW_LBR, last_write_fp);
  1018. X      WriteObject(y, NO_PREC);
  1019. X      fputs(KW_RBR, last_write_fp);
  1020. X    }
  1021. X    else WriteObject(y, DEFAULT_PREC);
  1022. X      }
  1023. X      if( DEFAULT_PREC <= outer_prec )  fputs(KW_RBR, last_write_fp);
  1024. X      break;
  1025. X
  1026. X
  1027. X    default:
  1028. X
  1029. X      Error(INTERN, &fpos(x), "WriteObject: type(x) = %s", Image(type(x)));
  1030. X      break;
  1031. X
  1032. X  } /* end switch */
  1033. X} /* end WriteObject */
  1034. X
  1035. X
  1036. X/*****************************************************************************/
  1037. X/*                                                                           */
  1038. X/*  AppendToFile(x, fnum, pos)                                               */
  1039. X/*                                                                           */
  1040. X/*  Append object x to file fnum, returning its fseek position in *pos.      */
  1041. X/*  Record the fact that this file has been updated.                         */
  1042. X/*                                                                           */
  1043. X/*****************************************************************************/
  1044. X
  1045. XAppendToFile(x, fnum, pos)
  1046. XOBJECT x;  FILE_NUM fnum;  int *pos;
  1047. X{ unsigned char buff[MAX_LINE], *str;
  1048. X  ifdebug(DPP, D, ProfileOn("AppendToFile"));
  1049. X  debug2(DFS, D, "AppendToFile( %s, %s )", EchoObject(null, x), FileName(fnum));
  1050. X
  1051. X  /* open file fnum for writing */
  1052. X  if( last_write_fnum != fnum )
  1053. X  { if( last_write_fnum != NO_FILE )  fclose(last_write_fp);
  1054. X    str = FileName(fnum);
  1055. X    if( strlen(str) + strlen(NEW_DATA_SUFFIX) >= MAX_LINE )
  1056. X      Error(FATAL, PosOfFile(fnum), "file name %s%s is too long",
  1057. X    str, NEW_DATA_SUFFIX);
  1058. X    sprintf(buff, "%s%s", str, NEW_DATA_SUFFIX);
  1059. X    last_write_fp = fopen(buff, "a");
  1060. X    if( last_write_fp == null )  Error(FATAL, &fpos(fvec[fnum]),
  1061. X        "cannot append to database file %s", buff);
  1062. X    last_write_fnum = fnum;
  1063. X  }
  1064. X
  1065. X  /* write x out */
  1066. X  *pos = (int) ftell(last_write_fp);
  1067. X  fputs(KW_LBR, last_write_fp);
  1068. X  WriteObject(x, NO_PREC);
  1069. X  fprintf(last_write_fp, "%s\n\n", KW_RBR);
  1070. X
  1071. X  /* record the fact that fnum has changed */
  1072. X  updated(fvec[fnum]) = TRUE;
  1073. X  ifdebug(DPP, D, ProfileOff("AppendToFile"));
  1074. X  debug0(DFS, D, "AppendToFile returning.");
  1075. X} /* end AppendToFile */
  1076. X
  1077. X
  1078. X/*@@**************************************************************************/
  1079. X/*                                                                           */
  1080. X/*  CloseFiles()                                                             */
  1081. X/*                                                                           */
  1082. X/*  Close all files and move new versions to the names of old versions.      */
  1083. X/*                                                                           */
  1084. X/*****************************************************************************/
  1085. X
  1086. XCloseFiles()
  1087. X{ FILE_NUM fnum;
  1088. X  unsigned char buff[MAX_LINE];
  1089. X  ifdebug(DPP, D, ProfileOn("CloseFiles"));
  1090. X  debug0(DFS, D, "CloseFiles()");
  1091. X
  1092. X  /* close off last file opened by AppendToFile above */
  1093. X  if( last_write_fnum != NO_FILE )  fclose(last_write_fp);
  1094. X
  1095. X  /* get rid of old database files */
  1096. X  for( fnum = FirstFile(SOURCE_FILE);  fnum != NO_FILE;  fnum = NextFile(fnum) )
  1097. X  { sprintf(buff, "%s%s", FileName(fnum), DATA_SUFFIX);
  1098. X    unlink(buff);
  1099. X  }
  1100. X
  1101. X  /* move any new database files to the old names, if updated */
  1102. X  for( fnum = FirstFile(DATABASE_FILE); fnum != NO_FILE; fnum = NextFile(fnum) )
  1103. X  { if( updated(fvec[fnum]) )
  1104. X    { sprintf(buff, "%s%s", string(fvec[fnum]), NEW_DATA_SUFFIX);
  1105. X      debug1(DFS, D, "unlink(%s)", string(fvec[fnum]));
  1106. X      unlink(string(fvec[fnum])); /* may fail if old version does not exist */
  1107. X      debug2(DFS, D, "link(%s, %s)", buff, string(fvec[fnum]));
  1108. X      if( link(buff, string(fvec[fnum])) != 0 )
  1109. X        Error(INTERN, no_fpos, "link(%s, %s) failed", buff, string(fvec[fnum]));
  1110. X      debug1(DFS, D, "unlink(%s)", buff);
  1111. X      if( unlink(buff) != 0 )
  1112. X           Error(INTERN, no_fpos, "unlink(%s) failed", buff);
  1113. X    }
  1114. X  }
  1115. X  debug0(DFS, D, "CloseFiles returning.");
  1116. X  ifdebug(DPP, D, ProfileOff("CloseFiles"));
  1117. X} /* end CloseFiles */
  1118. END_OF_FILE
  1119.   if test 35079 -ne `wc -c <'lout/z03.c'`; then
  1120.     echo shar: \"'lout/z03.c'\" unpacked with wrong size!
  1121.   fi
  1122.   # end of 'lout/z03.c'
  1123. fi
  1124. if test -f 'lout/z08.c' -a "${1}" != "-c" ; then 
  1125.   echo shar: Will not clobber existing file \"'lout/z08.c'\"
  1126. else
  1127.   echo shar: Extracting \"'lout/z08.c'\" \(36495 characters\)
  1128.   sed "s/^X//" >'lout/z08.c' <<'END_OF_FILE'
  1129. X/*@z08.c:Object Manifest:Manifest()@******************************************/
  1130. X/*                                                                           */
  1131. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.03)       */
  1132. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  1133. X/*                                                                           */
  1134. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  1135. X/*  Basser Department of Computer Science                                    */
  1136. X/*  The University of Sydney 2006                                            */
  1137. X/*  AUSTRALIA                                                                */
  1138. X/*                                                                           */
  1139. X/*  This program is free software; you can redistribute it and/or modify     */
  1140. X/*  it under the terms of the GNU General Public License as published by     */
  1141. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  1142. X/*  any later version.                                                       */
  1143. X/*                                                                           */
  1144. X/*  This program is distributed in the hope that it will be useful,          */
  1145. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  1146. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  1147. X/*  GNU General Public License for more details.                             */
  1148. X/*                                                                           */
  1149. X/*  You should have received a copy of the GNU General Public License        */
  1150. X/*  along with this program; if not, write to the Free Software              */
  1151. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  1152. X/*                                                                           */
  1153. X/*  FILE:         z08.c                                                      */
  1154. X/*  MODULE:       Object Manifest                                            */
  1155. X/*  EXTERNS:      Manifest()                                                 */
  1156. X/*                                                                           */
  1157. X/*****************************************************************************/
  1158. X#include "externs"
  1159. X
  1160. X#define errorcase()                            \
  1161. X                                    \
  1162. X    y = MakeWord("", &fpos(x));                        \
  1163. X    ReplaceNode(y, x);                            \
  1164. X    DisposeObject(x);                            \
  1165. X    x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE);    \
  1166. X    break;
  1167. X
  1168. X
  1169. X/*****************************************************************************/
  1170. X/*                                                                           */
  1171. X/*  static ReplaceWithSplit(x, bthr, fthr)                                   */
  1172. X/*                                                                           */
  1173. X/*  Replace object x with a SPLIT object, if threads for this object are     */
  1174. X/*  requested by bthr and/or fthr.                                           */
  1175. X/*                                                                           */
  1176. X/*****************************************************************************/
  1177. X
  1178. X#define ReplaceWithSplit(x, bthr, fthr)                    \
  1179. X   if( bthr[ROW] || bthr[COL] || fthr[ROW] || fthr[COL] )        \
  1180. X    x = insert_split(x, bthr, fthr)
  1181. X
  1182. Xstatic OBJECT insert_split(x, bthr, fthr)
  1183. XOBJECT x;  OBJECT bthr[2], fthr[2];
  1184. X{ OBJECT res, new_op;  int dim;
  1185. X  debug1(DOM, DD, "ReplaceWithSplit(%s, -)", EchoObject(null, x));
  1186. X  assert( type(x) != SPLIT, "ReplaceWithSplit: type(x) already SPLIT!" );
  1187. X  res = New(SPLIT);
  1188. X  FposCopy(fpos(res), fpos(x));
  1189. X  ReplaceNode(res, x);
  1190. X  for( dim = COL;  dim <= ROW;  dim++ )
  1191. X  { if( bthr[dim] || fthr[dim] )
  1192. X    { new_op = New(dim == COL ? COL_THR : ROW_THR);
  1193. X      thr_state(new_op) = NOTSIZED;
  1194. X      fwd(new_op, 1-dim) = 0;    /* will hold max frame_size */
  1195. X      back(new_op, 1-dim) = 0;    /* will hold max frame_origin */
  1196. X      FposCopy(fpos(new_op), fpos(x));
  1197. X      Link(res, new_op);
  1198. X      Link(new_op, x);
  1199. X      if( bthr[dim] )  Link(bthr[dim], new_op);
  1200. X      if( fthr[dim] )  Link(fthr[dim], new_op);
  1201. X    }
  1202. X    else Link(res, x);
  1203. X  }
  1204. X
  1205. X  debug1(DOM, DD, "ReplaceWithSplit returning %s", EchoObject(null, res));
  1206. X  return res;
  1207. X} /* end insert_split */
  1208. X
  1209. X
  1210. X/*@@**************************************************************************/
  1211. X/*                                                                           */
  1212. X/*  OBJECT ReplaceWithTidy(x)                                                */
  1213. X/*                                                                           */
  1214. X/*  Replace object x with a tidier version in which juxtapositions are       */
  1215. X/*  folded, etc.  If this is not possible, return the original object.       */
  1216. X/*                                                                           */
  1217. X/*****************************************************************************/
  1218. X
  1219. XOBJECT ReplaceWithTidy(x)
  1220. XOBJECT x;
  1221. X{
  1222. X  static unsigned char buff[MAX_LINE];
  1223. X  static int buff_len;
  1224. X  static FILE_POS buff_pos;
  1225. X
  1226. X  OBJECT link, y, tmp, res;
  1227. X  debug1(DOM, DD, "ReplaceWithTidy( %s )", EchoObject(null, x));
  1228. X  switch( type(x) )
  1229. X  {
  1230. X    case ACAT:
  1231. X    
  1232. X      /* flatten any sub-acats, recursively */
  1233. X      for( link = Down(x);  link != x;  link = NextDown(link) )
  1234. X      {    Child(y, link);
  1235. X    if( type(y) == ACAT )
  1236. X    { tmp = Down(y);
  1237. X      TransferLinks(tmp, y, link);
  1238. X      DisposeChild(link);
  1239. X      link = PrevDown(tmp);
  1240. X    }
  1241. X      }
  1242. X
  1243. X      /* now scan along and do the tidying */
  1244. X      res = nil;
  1245. X      buff_len = 0;
  1246. X      FposCopy(buff_pos, fpos(x));
  1247. X      for( link = Down(x); link != x; link = NextDown(link) )
  1248. X      {    Child(y, link);
  1249. X    if( type(y) == WORD )
  1250. X    { if( buff_len + strlen(string(y)) >= MAX_LINE )
  1251. X        Error(WARN, &fpos(y),"word is too long");
  1252. X      else
  1253. X      { if( buff_len == 0 )  FposCopy(buff_pos, fpos(y));
  1254. X        strcpy(&buff[buff_len], string(y));
  1255. X        buff_len += strlen(string(y));
  1256. X      }
  1257. X    }
  1258. X    else if( type(y) == GAP_OBJ )
  1259. X    { if( Down(y) != y || hspace(y) + vspace(y) > 0 )
  1260. X      { FontStripQuotes(buff, &buff_pos);
  1261. X        if( strlen(buff) > 0 )
  1262. X        { tmp = MakeWord(buff, &buff_pos);
  1263. X          buff_len = 0;
  1264. X          if( res == nil )
  1265. X          {    res = New(ACAT);
  1266. X        FposCopy(fpos(res), fpos(x));
  1267. X          }
  1268. X          Link(res, tmp);
  1269. X          Link(res, y);
  1270. X        }
  1271. X      }
  1272. X    }
  1273. X    else /* error */
  1274. X    { if( res != nil )  DisposeObject(res);
  1275. X      debug1(DOM, DD, "ReplaceWithTidy returning %s (unchanged)",
  1276. X            EchoObject(null, x));
  1277. X      return x;
  1278. X    }
  1279. X      }
  1280. X      FontStripQuotes(buff, &buff_pos);
  1281. X      tmp = MakeWord(buff, &buff_pos);
  1282. X      if( res == nil )  res = tmp;
  1283. X      else Link(res, tmp);
  1284. X      ReplaceNode(res, x);
  1285. X      DisposeObject(x);
  1286. X      debug1(DOM, DD, "ReplaceWithTidy returning %s", EchoObject(null, res));
  1287. X      return res;
  1288. X
  1289. X
  1290. X    case WORD:
  1291. X
  1292. X      FontStripQuotes(string(x), &fpos(x));
  1293. X      debug1(DOM, DD, "ReplaceWithTidy returning %s", EchoObject(null, x));
  1294. X      return x;
  1295. X
  1296. X
  1297. X    default:
  1298. X
  1299. X      debug1(DOM, DD, "ReplaceWithTidy returning %s (unchanged)",
  1300. X        EchoObject(null, x));
  1301. X      return x;
  1302. X
  1303. X  }
  1304. X} /* end ReplaceWithTidy */
  1305. X
  1306. X
  1307. X/*@@**************************************************************************/
  1308. X/*                                                                           */
  1309. X/*  static float GetScaleFactor(x, str)                                      */
  1310. X/*                                                                           */
  1311. X/*  Find a scale factor in object x and return it as a float, after checks.  */
  1312. X/*  Incorporate str in any error messages generated.                         */
  1313. X/*                                                                           */
  1314. X/*****************************************************************************/
  1315. X
  1316. Xstatic float GetScaleFactor(x, str)
  1317. XOBJECT x;  unsigned char *str;
  1318. X{ float scale_factor;
  1319. X  if( type(x) != WORD )
  1320. X  { Error(WARN, &fpos(x), "replacing invalid %s by 1.0", str);
  1321. X    scale_factor = 1.0;
  1322. X  }
  1323. X  else if( sscanf(string(x), "%f", &scale_factor) != 1 )
  1324. X  { Error(WARN, &fpos(x), "replacing invalid %s %s by 1.0", str, string(x));
  1325. X    scale_factor = 1.0;
  1326. X  }
  1327. X  else if( scale_factor < 0.01 )
  1328. X  { Error(WARN, &fpos(x), "replacing undersized %s %s by 1.0", str, string(x));
  1329. X    scale_factor = 1.0;
  1330. X  }
  1331. X  else if( scale_factor > 100 )
  1332. X  { Error(WARN, &fpos(x), "replacing oversized %s %s by 1.0", str, string(x));
  1333. X    scale_factor = 1.0;
  1334. X  }
  1335. X  return scale_factor;
  1336. X} /* GetScaleFactor */
  1337. X
  1338. X
  1339. Xstatic OBJECT nbt[2] = { nil, nil };        /* constant nil threads      */
  1340. Xstatic OBJECT nft[2] = { nil, nil };        /* constant nil threads      */
  1341. Xstatic OBJECT ntarget = nil;            /* constant nil target       */
  1342. X
  1343. X/*@@**************************************************************************/
  1344. X/*                                                                           */
  1345. X/*  OBJECT Manifest(x, env, style, bthr, fthr, target, crs, ok, need_expand) */
  1346. X/*                                                                           */
  1347. X/*  Manifest object x, interpreted in environment env and style style.       */
  1348. X/*  The result replaces x, and is returned also.                             */
  1349. X/*  The manifesting operation converts x from a pure parse tree object       */
  1350. X/*  containing closures and no threads, to an object ready for sizing,       */
  1351. X/*  with fonts propagated to the words, fill styles propagated to the        */
  1352. X/*  ACATs, and line spacings propagated to all interested parties.           */
  1353. X/*  All non-recursive, non-indefinite closures are expanded.                 */
  1354. X/*  Threads joining objects on a mark are constructed, and SPLIT objects     */
  1355. X/*  inserted, so that sizing becomes a trivial operation.                    */
  1356. X/*                                                                           */
  1357. X/*  Manifest will construct threads and pass them up as children of bthr[]   */
  1358. X/*  and fthr[] whenever non-nil values of these variables are passed in:     */
  1359. X/*                                                                           */
  1360. X/*      bthr[COL]            protrudes upwards from x                        */
  1361. X/*      fthr[COL]            protrudes downwards from x                      */
  1362. X/*      bthr[ROW]            protrudes leftwards from x                      */
  1363. X/*      fthr[ROW]            protrudes rightwards from x                     */
  1364. X/*                                                                           */
  1365. X/*  If *target != nil, Manifest will expand indefinite closures leading to   */
  1366. X/*  the first @Galley lying within an object of type *target.                */
  1367. X/*                                                                           */
  1368. X/*  Some objects x are not "real" in the sense that they do not give rise    */
  1369. X/*  to rectangles in the final printed document.  The left parameter of      */
  1370. X/*  @Wide and similar operators, and the gap following a concatenation       */
  1371. X/*  operator, are examples of such non-real objects.  The ok flag is true    */
  1372. X/*  when x is part of a real object.  This is needed because some things,    */
  1373. X/*  such as the insinuation of cross references and the breaking of          */
  1374. X/*  lines @Break ACAT objects, only apply to real objects.                   */
  1375. X/*                                                                           */
  1376. X/*  If *crs != nil, it points to a list of indexes to cross-references       */
  1377. X/*  which are to be insinuated into the manifested form of x if x is real.   */
  1378. X/*                                                                           */
  1379. X/*  If need_expand is TRUE it forces closure x to expand.                    */
  1380. X/*                                                                           */
  1381. X/*****************************************************************************/
  1382. X
  1383. XOBJECT Manifest(x, env, style, bthr, fthr, target, crs, ok, need_expand)
  1384. XOBJECT x, env;  STYLE *style;
  1385. XOBJECT bthr[2], fthr[2]; OBJECT *target, *crs;
  1386. XBOOLEAN ok, need_expand;
  1387. X{ OBJECT bt[2], ft[2], y, link, sym, tag, gaplink, g, ylink, yield, ytag, zlink;
  1388. X  OBJECT res, res_env, res_env2, hold_env, hold_env2, first_bt, last_ft, z;
  1389. X  OBJECT firsttag, firstres, prev;  float scale_factor;
  1390. X  int par, perp;  GAP res_gap;  unsigned res_inc;  STYLE new_style;
  1391. X  BOOLEAN still_backing, done, multiline, symbol_free;
  1392. X
  1393. X  debug2(DOM, D,   "[Manifest(%s %s )", Image(type(x)), EchoObject(null, x));
  1394. X  debug1(DOM, DD,  "  environment: %s", EchoObject(null, env));
  1395. X  debug6(DOM, DD,  "  style: %s;  target: %s;  threads: %s%s%s%s",
  1396. X    EchoStyle(style), SymName(*target),
  1397. X    bthr[COL] ? " up"    : "",  fthr[COL] ? " down"  : "",
  1398. X    bthr[ROW] ? " left"  : "",  fthr[ROW] ? " right" : "");
  1399. X
  1400. X  if( type(x) <= ACAT ) switch( type(x) )    /* breaks up oversize switch */
  1401. X  {
  1402. X
  1403. X    case CLOSURE:
  1404. X    
  1405. X      sym = actual(x);
  1406. X      StyleCopy(save_style(x), *style);
  1407. X      debug1(DOM, DD,  "  closure; sym = %s", SymName(sym));
  1408. X
  1409. X      /* expand parameters where possible, and find if they are all free */
  1410. X      symbol_free = TRUE;
  1411. X      for( link = Down(x);  link != x;  link = NextDown(link) )
  1412. X      { Child(y, link);
  1413. X    assert( type(y) == PAR, "Manifest/CLOSURE: type(y) != PAR!" );
  1414. X    Child(z, Down(y));
  1415. X    if( type(z) != WORD && !has_par(actual(y)) )
  1416. X    { if( is_tag(actual(y)) || is_key(actual(y)) || type(z) == NEXT )
  1417. X      { z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  1418. X        z = ReplaceWithTidy(z);
  1419. X      }
  1420. X    }
  1421. X    if( type(z) != WORD )  symbol_free = FALSE;
  1422. X      }
  1423. X
  1424. X      /* if all parameters are free of symbols, optimize environment */
  1425. X      if( symbol_free && imports(sym) == nil && enclosing(sym) != StartSym )
  1426. X      {    y = SearchEnv(env, enclosing(sym));
  1427. X    if( y != nil && type(y) == CLOSURE )
  1428. X    { env = SetEnv(y, nil);
  1429. X      hold_env2 = New(ACAT);  Link(hold_env2, env);
  1430. X    }
  1431. X    else
  1432. X    { Error(WARN, &fpos(x), "symbol %s used outside %s",
  1433. X        SymName(sym), SymName(enclosing(sym)));
  1434. X      hold_env2 = nil;
  1435. X    }
  1436. X      }
  1437. X      else hold_env2 = nil;
  1438. X
  1439. X      if( has_target(sym) && !need_expand )
  1440. X      {
  1441. X    /* convert symbols with targets to unsized galleys */
  1442. X    OBJECT hd = New(HEAD);
  1443. X    FposCopy(fpos(hd), fpos(x));
  1444. X    actual(hd) = sym;
  1445. X    backward(hd) = TargetSymbol(x, &whereto(hd));
  1446. X    ready_galls(hd) = nil;
  1447. X    must_expand(hd) = TRUE;
  1448. X    sized(hd) = FALSE;
  1449. X    ReplaceNode(hd, x);
  1450. X    Link(hd, x);
  1451. X    AttachEnv(env, x);
  1452. X    x = hd;
  1453. X          threaded(x) = bthr[COL] != nil || fthr[COL] != nil;
  1454. X    ReplaceWithSplit(x, bthr, fthr);
  1455. X      }
  1456. X      else if(
  1457. X        *target == sym                ? (*target = nil, TRUE) :
  1458. X        need_expand                ? TRUE  :
  1459. X        uses_galley(sym) && !recursive(sym) ? TRUE  :
  1460. X        !indefinite(sym) && !recursive(sym) ? TRUE  :
  1461. X        indefinite(sym)  && *target != nil  ? SearchUses(sym, *target)
  1462. X                            : FALSE
  1463. X         )
  1464. X      {
  1465. X    /* expand the closure and manifest the result */
  1466. X    debug1(DOM, DD, "expanding; style: %s", EchoStyle(style));
  1467. X    x = ClosureExpand(x, env, style, TRUE, crs, &res_env);
  1468. X    hold_env = New(ACAT);  Link(hold_env, res_env);
  1469. X    debug1(DOM, DD, "recursive call; style: %s", EchoStyle(style));
  1470. X    x = Manifest(x, res_env, style, bthr, fthr, target, crs, ok, FALSE);
  1471. X    DisposeObject(hold_env);
  1472. X      }
  1473. X      else
  1474. X      {
  1475. X    /* indefinite symbol, leave unexpanded */
  1476. X    AttachEnv(env, x);
  1477. X    threaded(x) = bthr[COL] != nil || fthr[COL] != nil;
  1478. X    debug0(DOM, DD,  "  closure; calling ReplaceWithSplit");
  1479. X    ReplaceWithSplit(x, bthr, fthr);
  1480. X      }
  1481. X      if( hold_env2 != nil )  DisposeObject(hold_env2);
  1482. X      break;
  1483. X
  1484. X
  1485. X    case NULL_CLOS:
  1486. X
  1487. X      StyleCopy(save_style(x), *style);
  1488. X      ReplaceWithSplit(x, bthr, fthr);
  1489. X      break;
  1490. X
  1491. X
  1492. X    case CROSS:
  1493. X    
  1494. X      assert( Down(x) != x && LastDown(x) != Down(x), "Manifest: CROSS child!");
  1495. X      debug0(DCR, DD, "  calling CrossExpand from Manifest/CROSS");
  1496. X      x = CrossExpand(x, env, style, TRUE, crs, &res_env);
  1497. X      assert( type(x) == CLOSURE, "Manifest/CROSS: type(x)!" );
  1498. X      hold_env = New(ACAT);  Link(hold_env, res_env);
  1499. X      /* expand here (calling Manifest immediately makes unwanted cr) */
  1500. X      x = ClosureExpand(x, res_env, style, FALSE, crs, &res_env2);
  1501. X      hold_env2 = New(ACAT);  Link(hold_env2, res_env2);
  1502. X      x = Manifest(x, res_env2, style, bthr, fthr, target, crs, ok, TRUE);
  1503. X      DisposeObject(hold_env);
  1504. X      DisposeObject(hold_env2);
  1505. X      break;
  1506. X
  1507. X
  1508. X    case WORD:
  1509. X    
  1510. X      if( !ok || *crs == nil )
  1511. X      {    word_font(x) = font(*style);
  1512. X    ReplaceWithSplit(x, bthr, fthr);
  1513. X    break;
  1514. X      }
  1515. X      y = New(ACAT);
  1516. X      FposCopy(fpos(y), fpos(x));
  1517. X      ReplaceNode(y, x);
  1518. X      Link(y, x);  x = y;
  1519. X      /* NB NO BREAK! */
  1520. X
  1521. X
  1522. X    case ACAT:
  1523. X    
  1524. X      StyleCopy(save_style(x), *style);
  1525. X      assert(Down(x) != x, "Manifest: ACAT!" );
  1526. X      link = Down(x);  Child(y, link);
  1527. X      assert( type(y) != GAP_OBJ, "Manifest ACAT: GAP_OBJ is first!" );
  1528. X      multiline = FALSE;
  1529. X
  1530. X      /* manifest first child and insert any cross references */
  1531. X      if( type(y) == WORD )  word_font(y) = font(*style);
  1532. X      else y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE);
  1533. X      if( ok && *crs != nil )
  1534. X      {    
  1535. X    debug1(DCR, D, "  insinuating %s", EchoObject(null, *crs));
  1536. X    TransferLinks(Down(*crs), *crs, link);
  1537. X    DisposeObject(*crs);
  1538. X    *crs = nil;
  1539. X      }
  1540. X      prev = y;
  1541. X
  1542. X      for( gaplink = Down(link);  gaplink != x;  gaplink = NextDown(link) )
  1543. X      {
  1544. X    Child(g, gaplink);
  1545. X    assert( type(g) == GAP_OBJ, "Manifest ACAT: no GAP_OBJ!" );
  1546. X    link = NextDown(gaplink);
  1547. X    assert( link != x, "Manifest ACAT: GAP_OBJ is last!" );
  1548. X    Child(y, link);
  1549. X    assert( type(y) != GAP_OBJ, "Manifest ACAT: double GAP_OBJ!" );
  1550. X
  1551. X    /* manifest the next child */
  1552. X        debug1(DOM, DD, "  in ACAT (3), style = %s", EchoStyle(style));
  1553. X    if( type(y) == WORD ) word_font(y) = font(*style);
  1554. X    else y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE);
  1555. X
  1556. X    /* manifest the gap object */
  1557. X    if( Down(g) != g )
  1558. X    {
  1559. X      /* explicit & operator whose value is g's child */
  1560. X      Child(z, Down(g));
  1561. X      z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  1562. X      z = ReplaceWithTidy(z);
  1563. X      GetGap(z, style, &gap(g), &res_inc);
  1564. X      vspace(g) = hspace(g) = 0;
  1565. X    }
  1566. X    else
  1567. X    {
  1568. X      /* implicit & operator */
  1569. X      GapCopy(gap(g), space_gap(*style));
  1570. X      width(gap(g)) = width(gap(g)) * (vspace(g) + hspace(g));
  1571. X      if( vspace(g) > 0 && is_definite(type(y)) )  multiline = TRUE;
  1572. X    }
  1573. X        debug1(DOM, DD, "  in ACAT, gap = %s", EchoLength(width(gap(g))));
  1574. X
  1575. X    /* compress adjacent juxtaposed words of equal font */
  1576. X    if( type(y) == WORD && width(gap(g)) == 0 && vspace(g)+hspace(g) == 0 )
  1577. X    { if( units(gap(g)) == FIXED_UNIT && mode(gap(g)) == EDGE_MODE )
  1578. X      { if( prev!=nil && type(prev)==WORD && word_font(prev)==word_font(y) )
  1579. X        { if( !mark(gap(g)) )
  1580. X          {    if( strlen(string(prev)) + strlen(string(y)) >= MAX_LINE )
  1581. X          Error(FATAL, &fpos(prev), "word %s%s is too long",
  1582. X            string(prev), string(y));
  1583. X        z = y;
  1584. X        y = MakeWordTwo(string(prev), string(y), &fpos(prev));
  1585. X        word_font(y) = word_font(prev);
  1586. X        MoveLink(link, y, CHILD);
  1587. X        DisposeObject(z);
  1588. X        DisposeChild(Up(prev));
  1589. X        DisposeChild(gaplink);
  1590. X          }
  1591. X        }
  1592. X      }
  1593. X    }
  1594. X    prev = y;
  1595. X
  1596. X    /* insinuate any cross-references */
  1597. X    if( ok && *crs != nil )
  1598. X    {
  1599. X      debug1(DCR, D, "  insinuating %s", EchoObject(null, *crs));
  1600. X      TransferLinks(Down(*crs), *crs, link);
  1601. X      DisposeObject(*crs);
  1602. X      *crs = nil;
  1603. X    }
  1604. X
  1605. X      }
  1606. X
  1607. X      /* implement FILL_OFF break option if required */
  1608. X      if( ok && multiline && fill_style(*style) == FILL_UNDEF )
  1609. X    Error(FATAL, &fpos(x), "missing %s operator or option", KW_BREAK);
  1610. X      if( ok && multiline && fill_style(*style) == FILL_OFF )
  1611. X      {    OBJECT last_acat = x, new_acat;
  1612. X    x = New(VCAT);
  1613. X    ReplaceNode(x, last_acat);
  1614. X    Link(x, last_acat);
  1615. X    for( link = Down(last_acat); link != last_acat; link = NextDown(link) )
  1616. X    { Child(g, link);
  1617. X      if( type(g) == GAP_OBJ && mode(gap(g)) != NO_MODE && vspace(g) > 0 )
  1618. X      { link = PrevDown(link);
  1619. X        MoveLink(NextDown(link), x, PARENT);
  1620. X        GapCopy(gap(g), line_gap(*style));
  1621. X        width(gap(g)) *= vspace(g);
  1622. X        new_acat = New(ACAT);
  1623. X        if( hspace(g) > 0 )
  1624. X        { z = MakeWord("", &fpos(g));
  1625. X          Link(new_acat, z);
  1626. X          z = New(GAP_OBJ);
  1627. X          hspace(z) = hspace(g);
  1628. X          vspace(z) = 0;
  1629. X          GapCopy(gap(z), space_gap(*style));
  1630. X          width(gap(z)) *= hspace(z);
  1631. X          Link(new_acat, z);
  1632. X        }
  1633. X        TransferLinks(NextDown(link), last_acat, new_acat);
  1634. X        StyleCopy(save_style(new_acat), *style);
  1635. X        Link(x, new_acat);
  1636. X        last_acat = new_acat;
  1637. X        link = last_acat;
  1638. X      }
  1639. X    }
  1640. X      }
  1641. X
  1642. X      ReplaceWithSplit(x, bthr, fthr);
  1643. X      break;
  1644. X
  1645. X
  1646. X    default:
  1647. X
  1648. X      Error(INTERN, &fpos(x), "Manifest: no case for type %s", Image(type(x)));
  1649. X      break;
  1650. X
  1651. X  } /* end <= ACAT */
  1652. X  else if( type(x) <= VCAT )  switch( type(x) )
  1653. X  {
  1654. X
  1655. X    case HCAT:
  1656. X    case VCAT:
  1657. X    
  1658. X      par = type(x) == HCAT ? ROW : COL;
  1659. X      perp = 1 - par;
  1660. X      link = Down(x);
  1661. X      gaplink = NextDown(link);
  1662. X      assert( link!=x && gaplink!=x, "Manifest/VCAT: less than two children!" );
  1663. X      Child(y, link);  Child(g, gaplink);
  1664. X
  1665. X      /* set bt and ft threads for y */
  1666. X      bt[perp] = bthr[perp];
  1667. X      ft[perp] = fthr[perp];
  1668. X      first_bt = bt[par] = bthr[par] ? New(THREAD) : nil;
  1669. X      ft[par] = join(gap(g)) ? New(THREAD) : nil;
  1670. X      still_backing = first_bt != nil;
  1671. X
  1672. X      /* manifest y and insinuate any cross-references */
  1673. X      y = Manifest(y, env, style, bt, ft, target, crs, ok, FALSE);
  1674. X      if( type(x) == VCAT && ok && *crs != nil )
  1675. X      {
  1676. X    debug1(DCR, D, "  insinuating %s", EchoObject(null, *crs));
  1677. X    TransferLinks(Down(*crs), *crs, link);
  1678. X    DisposeObject(*crs);
  1679. X    *crs = nil;
  1680. X      }
  1681. X
  1682. X      /* manifest the remaining children */
  1683. X      while( g != nil )
  1684. X      {    
  1685. X    /* manifest the gap object, store it in gap(g), add perp threads */
  1686. X    assert( type(g) == GAP_OBJ, "Manifest/VCAT: type(g) != GAP_OBJECT!" );
  1687. X    assert( Down(g) != g, "Manifest/VCAT: GAP_OBJ has no child!" );
  1688. X    Child(z, Down(g));
  1689. X    debug1(DOM, DD, "manifesting gap, style = %s", EchoStyle(style));
  1690. X    z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  1691. X    debug1(DOM, DD, "replacing with tidy, style = %s", EchoStyle(style));
  1692. X    z = ReplaceWithTidy(z);
  1693. X    debug1(DOM, DD, "calling GetGap, style = %s", EchoStyle(style));
  1694. X    GetGap(z, style, &gap(g), &res_inc);
  1695. X    if( bt[perp] )  Link(bt[perp], g);
  1696. X    if( ft[perp] )  Link(ft[perp], g);
  1697. X
  1698. X    /* find the next child y, and following gap if any */
  1699. X    link = NextDown(gaplink);
  1700. X    assert( link != x, "Manifest/VCAT: GAP_OBJ is last child!" );
  1701. X    Child(y, link);
  1702. X    gaplink = NextDown(link);
  1703. X    if( gaplink == x )  g = nil;
  1704. X    else Child(g, gaplink);
  1705. X
  1706. X    /* set bt and ft threads for y */
  1707. X    last_ft = ft[par];
  1708. X    bt[par] = ft[par] ? New(THREAD) : nil;
  1709. X    ft[par] = g != nil ? join(gap(g)) ? New(THREAD) : nil
  1710. X               : fthr[par]    ? New(THREAD) : nil;
  1711. X
  1712. X    /* manifest y and insinuate any cross references */
  1713. X    y = Manifest(y, env, style, bt, ft, target, crs, ok, FALSE);
  1714. X    if( type(x) == VCAT && ok && *crs != nil )
  1715. X        {
  1716. X      debug1(DCR, D, "  insinuating %s", EchoObject(null, *crs));
  1717. X      TransferLinks(Down(*crs), *crs, link);
  1718. X      DisposeObject(*crs);
  1719. X      *crs = nil;
  1720. X        }
  1721. X
  1722. X    if( bt[par] )    /* then thread lists last_ft and bt[par] must merge */
  1723. X    { OBJECT llink, rlink, lthread, rthread;  BOOLEAN goes_through;
  1724. X      assert( Down(bt[par]) != bt[par], "Manifest: bt[par] no children!" );
  1725. X      assert( last_ft!=nil && Down(last_ft)!=last_ft, "Manifest:last_ft!" );
  1726. X
  1727. X      /* check whether marks run right through y in par direction */
  1728. X      goes_through = FALSE;
  1729. X      if( ft[par] )
  1730. X      { assert( Down(ft[par]) != ft[par], "Manifest: ft[par] child!" );
  1731. X        Child(lthread, LastDown(bt[par]));
  1732. X        Child(rthread, LastDown(ft[par]));
  1733. X        goes_through = lthread == rthread;
  1734. X      }
  1735. X
  1736. X      /* merge the thread lists */
  1737. X      llink = Down(last_ft);  rlink = Down(bt[par]);
  1738. X      while( llink != last_ft && rlink != bt[par] )
  1739. X      { Child(lthread, llink);
  1740. X        Child(rthread, rlink);
  1741. X        assert( lthread != rthread, "Manifest: lthread == rthread!" );
  1742. X        MergeNode(lthread, rthread);
  1743. X        llink = NextDown(llink);
  1744. X        rlink = NextDown(rlink);
  1745. X      }
  1746. X
  1747. X      /* attach leftover back threads to first_bt if required */
  1748. X      if( rlink != bt[par] )
  1749. X      { 
  1750. X        /* ***
  1751. X        Error(WARN, &fpos(y), type(x) == VCAT ?
  1752. X          "number of columns above exceeds number here" :
  1753. X          "number of rows to left exceeds number here");
  1754. X        *** */
  1755. X        if( still_backing )  TransferLinks(rlink, bt[par], first_bt);
  1756. X      }
  1757. X      DisposeObject(bt[par]);
  1758. X
  1759. X      /* attach leftover forward threads to ft[par] if required */
  1760. X      if( llink != last_ft )
  1761. X      {
  1762. X        /* ***
  1763. X        Error(WARN, &fpos(y), type(x) == VCAT ?
  1764. X          "number of columns here exceeds number above" :
  1765. X          "number of rows here exceeds number to left");
  1766. X        *** */
  1767. X        if( goes_through )  TransferLinks(llink, last_ft, ft[par]);
  1768. X      }
  1769. X      DisposeObject(last_ft);
  1770. X
  1771. X      if( !goes_through )  still_backing = FALSE;
  1772. X
  1773. X    }
  1774. X    else still_backing = FALSE;
  1775. X
  1776. X      } /* end while */
  1777. X
  1778. X      /* export par threads */
  1779. X      if( fthr[par] )  MergeNode(fthr[par], ft[par]);
  1780. X      if( bthr[par] )  MergeNode(bthr[par], first_bt);
  1781. X      break;
  1782. X
  1783. X
  1784. X    default:
  1785. X
  1786. X      Error(INTERN, &fpos(x), "Manifest: no case for type %s", Image(type(x)));
  1787. X      break;
  1788. X
  1789. X  }
  1790. X  else switch( type(x) )
  1791. X  {
  1792. X
  1793. X    case WIDE:
  1794. X    case HIGH:
  1795. X    
  1796. X      Child(y, Down(x));
  1797. X      y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  1798. X      y = ReplaceWithTidy(y);
  1799. X      GetGap(y, style, &res_gap, &res_inc);
  1800. X      if( res_inc != ABS || mode(res_gap) != EDGE_MODE ||
  1801. X    units(res_gap) != FIXED_UNIT )
  1802. X      {    Error(WARN, &fpos(y), "replacing invalid left parameter of %s by 2i",
  1803. X            Image(type(x)) );
  1804. X    units(res_gap) = FIXED_UNIT;
  1805. X    width(res_gap) = 2*IN;
  1806. X      }
  1807. X      SetConstraint(constraint(x), MAX_LEN, width(res_gap), MAX_LEN);
  1808. X      DisposeChild(Down(x));
  1809. X      /* NB NO BREAK! */
  1810. X
  1811. X
  1812. X    case HCONTRACT:
  1813. X    case VCONTRACT:
  1814. X    case HEXPAND:
  1815. X    case VEXPAND:
  1816. X    case PADJUST:
  1817. X    case HADJUST:
  1818. X    case VADJUST:
  1819. X    case ONE_COL:
  1820. X    case ONE_ROW:
  1821. X    
  1822. X      par = (type(x)==ONE_COL || type(x)==HEXPAND || type(x) == HCONTRACT ||
  1823. X         type(x)==PADJUST || type(x)==HADJUST || type(x)==WIDE) ? COL : ROW;
  1824. X      Child(y, Down(x));
  1825. X
  1826. X      /* manifest the child, propagating perp threads and suppressing pars */
  1827. X      bt[par] = ft[par] = nil;
  1828. X      bt[1-par] = bthr[1-par];  ft[1-par] = fthr[1-par];
  1829. X      y = Manifest(y, env, style, bt, ft, target, crs, ok, FALSE);
  1830. X
  1831. X      /* replace with split object if par threads needed */
  1832. X      bt[par] = bthr[par];  ft[par] = fthr[par];
  1833. X      bt[1-par] = ft[1-par] = nil;
  1834. X      ReplaceWithSplit(x, bt, ft);
  1835. X      break;
  1836. X
  1837. X
  1838. X    case ROTATE:
  1839. X
  1840. X      Child(y, Down(x));
  1841. X      y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  1842. X      y = ReplaceWithTidy(y);
  1843. X      GetGap(y, style, &res_gap, &res_inc);
  1844. X      if( res_inc != ABS || mode(res_gap) != EDGE_MODE ||
  1845. X        units(res_gap) != DEG_UNIT )
  1846. X      {    Error(WARN, &fpos(y), "replacing invalid left parameter of %s by 0d",
  1847. X            Image(type(x)) );
  1848. X    units(res_gap) = DEG_UNIT;
  1849. X    width(res_gap) = 0;
  1850. X      }
  1851. X      sparec(constraint(x)) = width(res_gap);
  1852. X      DisposeChild(Down(x));
  1853. X      Child(y, Down(x));
  1854. X      y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE);
  1855. X      ReplaceWithSplit(x, bthr, fthr);
  1856. X      break;
  1857. X
  1858. X
  1859. X    case HSCALE:
  1860. X    case VSCALE:
  1861. X
  1862. X      Child(y, Down(x));
  1863. X      y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE);
  1864. X      ReplaceWithSplit(x, bthr, fthr);
  1865. X      break;
  1866. X
  1867. X
  1868. X    case SCALE:
  1869. X
  1870. X      Child(y, Down(x));
  1871. X      y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  1872. X      y = ReplaceWithTidy(y);
  1873. X      if( type(y) != ACAT )
  1874. X      { scale_factor = GetScaleFactor(y, "scale factor");
  1875. X        bc(constraint(x)) = fc(constraint(x)) = scale_factor * SF;
  1876. X      }
  1877. X      else
  1878. X      {
  1879. X    /* get horizontal scale factor */
  1880. X    Child(z, Down(y));
  1881. X    scale_factor = GetScaleFactor(z, "horizontal scale factor");
  1882. X        bc(constraint(x)) = scale_factor * SF;
  1883. X
  1884. X    /* get vertical scale factor */
  1885. X    Child(z, LastDown(y));
  1886. X    scale_factor = GetScaleFactor(z, "vertical scale factor");
  1887. X        fc(constraint(x)) = scale_factor * SF;
  1888. X      }
  1889. X      DisposeChild(Down(x));
  1890. X      Child(y, LastDown(x));
  1891. X      y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE);
  1892. X      ReplaceWithSplit(x, bthr, fthr);
  1893. X      break;
  1894. X
  1895. X
  1896. X    case YIELD:
  1897. X
  1898. X      Error(FATAL, &fpos(x), "%s outside of %s", KW_YIELD, KW_CASE);
  1899. X      break;
  1900. X
  1901. X
  1902. X    case CASE:
  1903. X
  1904. X      /* make sure left parameter (the tag) is in order */
  1905. X      debug0(DOM, DD, "  manifesting CASE now");
  1906. X      Child(tag, Down(x));
  1907. X      debug1(DOM, DD, "  manifesting CASE tag %s now", EchoObject(null, tag));
  1908. X      tag = Manifest(tag, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  1909. X      tag = ReplaceWithTidy(tag);
  1910. X      /* *** allowing this now; non-word matches "else" only ***
  1911. X      if( type(tag) != WORD )
  1912. X      {    Error(WARN, &fpos(tag), "%s deleted: left parameter is not a word",
  1913. X      KW_CASE);
  1914. X    errorcase();
  1915. X      }
  1916. X      *** */
  1917. X
  1918. X      /* make sure the right parameter is an ACAT */
  1919. X      Child(y, LastDown(x));
  1920. X      if( type(y) == YIELD )
  1921. X      {    z = New(ACAT);
  1922. X    MoveLink(Up(y), z, PARENT);
  1923. X    Link(x, z);
  1924. X    y = z;
  1925. X      }
  1926. X      if( type(y) != ACAT )
  1927. X      {    Error(WARN, &fpos(y), "%s deleted: right parameter is malformed",
  1928. X      KW_CASE);
  1929. X    errorcase();
  1930. X      }
  1931. X
  1932. X      /* hunt through right parameter for res, the selected case */
  1933. X      res = nil;  firsttag = nil;
  1934. X      for( ylink = Down(y); ylink != y && res == nil; ylink = NextDown(ylink) )
  1935. X      {    Child(yield, ylink);
  1936. X    if( type(yield) == GAP_OBJ )  continue;
  1937. X    if( type(yield) != YIELD )
  1938. X    { Error(WARN, &fpos(yield), "%s contains non-%s", KW_CASE, KW_YIELD);
  1939. X      break;
  1940. X    }
  1941. X    Child(ytag, Down(yield));
  1942. X    ytag = Manifest(ytag, env, style, nbt, nft, &ntarget, crs, FALSE,FALSE);
  1943. X    ytag = ReplaceWithTidy(ytag);
  1944. X    if( type(ytag) == WORD )
  1945. X    { if( firsttag == nil )
  1946. X      { firsttag = ytag;
  1947. X        Child(firstres, LastDown(yield));
  1948. X      }
  1949. X      if( (type(tag) == WORD && strcmp(string(ytag), string(tag)) == 0) ||
  1950. X          strcmp(string(ytag), "else"     ) == 0 )
  1951. X      { Child(res, LastDown(yield));
  1952. X        break;
  1953. X      }
  1954. X    }
  1955. X    else if( type(ytag) == ACAT )
  1956. X    { z = ytag;
  1957. X      for( zlink = Down(z);  zlink != z;  zlink = NextDown(zlink) )
  1958. X      { Child(ytag, zlink);
  1959. X        if( type(ytag) == GAP_OBJ )  continue;
  1960. X        if( type(ytag) != WORD )
  1961. X        { Error(WARN,&fpos(ytag),"error in left parameter of %s",KW_YIELD);
  1962. X          break;
  1963. X        }
  1964. X        if( firsttag == nil )
  1965. X        { firsttag = ytag;
  1966. X          Child(firstres, LastDown(yield));
  1967. X        }
  1968. X        if( (type(tag) == WORD && strcmp(string(ytag), string(tag)) == 0) ||
  1969. X            strcmp(string(ytag), "else"     ) == 0 )
  1970. X        { Child(res, LastDown(yield));
  1971. X          break;
  1972. X        }
  1973. X      }
  1974. X    }
  1975. X    else Error(WARN,&fpos(ytag),"error in left parameter of %s",KW_YIELD);
  1976. X      }
  1977. X      if( res == nil )
  1978. X      { if( firsttag != nil )
  1979. X    { Error(WARN, &fpos(tag), "replacing unkown %s option %s by %s",
  1980. X        KW_CASE, string(tag), string(firsttag));
  1981. X      res = firstres;
  1982. X    }
  1983. X    else
  1984. X    { Error(WARN, &fpos(tag), "%s deleted: selection %s unknown",
  1985. X        KW_CASE, string(tag));
  1986. X      errorcase();
  1987. X    }
  1988. X      }
  1989. X
  1990. X      /* now manifest the result and replace x with it */
  1991. X      DeleteLink(Up(res));
  1992. X      ReplaceNode(res, x);
  1993. X      DisposeObject(x);
  1994. X      x = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE);
  1995. X      break;
  1996. X
  1997. X
  1998. X    case FONT:
  1999. X    case SPACE:
  2000. X    case BREAK:
  2001. X    
  2002. X      assert( Down(x) != x && NextDown(Down(x)) != x, "Manifest: FONT!" );
  2003. X      StyleCopy(new_style, *style);
  2004. X      Child(y, Down(x));
  2005. X      y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  2006. X      y = ReplaceWithTidy(y);
  2007. X      if( type(x) == FONT )       FontChange(&new_style, y);
  2008. X      else if( type(x) == SPACE ) SpaceChange(&new_style, y);
  2009. X      else              BreakChange(&new_style, y);
  2010. X      DisposeChild(Down(x));
  2011. X      Child(y, Down(x));
  2012. X      y = Manifest(y, env, &new_style, bthr, fthr, target, crs, ok, FALSE);
  2013. X      DeleteLink(Down(x));
  2014. X      MergeNode(y, x);  x = y;
  2015. X      break;
  2016. X
  2017. X
  2018. X    case NEXT:
  2019. X
  2020. X      assert( Down(x) != x, "Manifest/NEXT: Down(x) == x!" );
  2021. X      Child(y, Down(x));
  2022. X      debug1(DCS, D, "  Manifesting Next( %s, 1 )", EchoObject(null, y));
  2023. X      y = Manifest(y, env, style, bthr, fthr, target, crs, FALSE, FALSE);
  2024. X      debug1(DCS, D, "  calling Next( %s, 1 )", EchoObject(null, y));
  2025. X      done = FALSE;
  2026. X      y = Next(y, 1, &done);
  2027. X      debug2(DCS, D, "  Next(done = %s) returning %s",
  2028. X            bool(done), EchoObject(null, y));
  2029. X      DeleteLink(Down(x));
  2030. X      MergeNode(y, x);  x = y;
  2031. X      break;
  2032. X
  2033. X
  2034. X    case OPEN:
  2035. X
  2036. X      Child(y, Down(x));
  2037. X      Child(res, LastDown(x));
  2038. X      if( type(y) == CLOSURE )
  2039. X      { AttachEnv(env, y);
  2040. X    StyleCopy(save_style(y), *style);
  2041. X    res_env = SetEnv(y, nil);
  2042. X    hold_env = New(ACAT);  Link(hold_env, res_env);
  2043. X    res = Manifest(res, res_env, style, bthr, fthr, target, crs, ok, FALSE);
  2044. X    DisposeObject(hold_env);
  2045. X      }
  2046. X      else if( type(y) == CROSS )
  2047. X      {    debug0(DCR, DD, "  calling CrossExpand from Manifest/OPEN");
  2048. X    y = CrossExpand(y, env, style, TRUE, crs, &res_env);
  2049. X    AttachEnv(res_env, y);
  2050. X    res_env = SetEnv(y, env);
  2051. X    hold_env = New(ACAT);  Link(hold_env, res_env);
  2052. X    res = Manifest(res, res_env, style, bthr, fthr, target, crs, ok, FALSE);
  2053. X    DisposeObject(hold_env);
  2054. X      }
  2055. X      else
  2056. X      {    Error(WARN, &fpos(y), "invalid left parameter of %s", KW_OPEN);
  2057. X    res = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE);
  2058. X      }
  2059. X      ReplaceNode(res, x);
  2060. X      DisposeObject(x);
  2061. X      x = res;
  2062. X      break;
  2063. X
  2064. X
  2065. X    case TAGGED:
  2066. X
  2067. X      /* make sure first argument is a cross-reference */
  2068. X      assert( Down(x) != x && NextDown(Down(x)) != x &&
  2069. X    NextDown(NextDown(Down(x))) == x, "Manifest TAGGED: children!" );
  2070. X      Child(y, Down(x));
  2071. X      if( type(y) != CROSS )
  2072. X      {    Error(WARN, &fpos(y), "left parameter of %s is not a cross-reference",
  2073. X                    KW_TAGGED);
  2074. X    errorcase();
  2075. X      }
  2076. X
  2077. X      /* make sure the arguments of the cross-reference are OK */
  2078. X      Child(z, Down(y));
  2079. X      if( type(z) != CLOSURE )
  2080. X      {    Error(WARN,&fpos(y),"left parameter of %s must be a symbol", KW_TAGGED);
  2081. X    errorcase();
  2082. X      }
  2083. X      if( !has_tag(actual(z)) )
  2084. X      {    Error(WARN, &fpos(z), "symbol %s illegal with %s since it has no %s",
  2085. X            SymName(actual(z)), KW_TAGGED, KW_TAG);
  2086. X    errorcase();
  2087. X      }
  2088. X      Child(z, NextDown(Down(y)));
  2089. X      z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  2090. X      if( type(z) == WORD && strcmp(string(z), KW_PRECEDING) == 0 )
  2091. X    cross_type(y) = CROSS_PREC;
  2092. X      else if( type(z) == WORD && strcmp(string(z), KW_FOLLOWING) == 0 )
  2093. X    cross_type(y) = CROSS_FOLL;
  2094. X      else
  2095. X      {    Error(WARN, &fpos(z), "%s of left parameter of %s must be %s or %s",
  2096. X        KW_TAG, KW_TAGGED, KW_PRECEDING, KW_FOLLOWING);
  2097. X    errorcase();
  2098. X      }
  2099. X
  2100. X      /* make sure second argument (the new key) is ok */
  2101. X      Child(tag, LastDown(x));
  2102. X      tag = Manifest(tag, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  2103. X      tag = ReplaceWithTidy(tag);
  2104. X      if( type(tag) != WORD )
  2105. X      {    Error(WARN, &fpos(tag), "right parameter of %s must be a simple word",
  2106. X                                KW_TAGGED);
  2107. X    ifdebug(DOM, D, EchoObject(stderr, tag));
  2108. X    errorcase();
  2109. X      }
  2110. X
  2111. X      /* assemble insinuated cross reference which replaces x */
  2112. X      ReplaceNode(tag, z);
  2113. X      DisposeObject(z);
  2114. X      ReplaceNode(y, x);
  2115. X      DisposeObject(x);
  2116. X      x = y;
  2117. X      ReplaceWithSplit(x, bthr, fthr);
  2118. X      break;
  2119. X
  2120. X
  2121. X    case GRAPHIC:
  2122. X
  2123. X      debug1(DRS, DD, "  graphic style in Manifest = %s", EchoStyle(style));
  2124. X      Child(y, LastDown(x));
  2125. X      y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE);
  2126. X      StyleCopy(save_style(x), *style);
  2127. X      Child(y, Down(x));
  2128. X      y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  2129. X      ReplaceWithSplit(x, bthr, fthr);
  2130. X      break;
  2131. X    
  2132. X
  2133. X    case INCGRAPHIC:
  2134. X    case SINCGRAPHIC:
  2135. X
  2136. X      Child(y, Down(x));
  2137. X      y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE);
  2138. X      y = ReplaceWithTidy(y);
  2139. X      if( type(y) != WORD )
  2140. X      { Error(WARN, &fpos(y), "%s deleted: invalid right parameter",
  2141. X      type(x) == INCGRAPHIC ? KW_INCGRAPHIC : KW_SINCGRAPHIC);
  2142. X    errorcase();
  2143. X      }
  2144. X      /* *** no longer defining these files (uses too many file numbers) ***
  2145. X      sparec(constraint(x)) = DefineFile(MakeWord(string(y), &fpos(y)),
  2146. X    INCGRAPHIC_FILE, type(x)==INCGRAPHIC ? INCLUDE_PATH : SYSINCLUDE_PATH);
  2147. X      *** */
  2148. X      ReplaceWithSplit(x, bthr, fthr);
  2149. X      break;
  2150. X    
  2151. X
  2152. X    default:
  2153. X
  2154. X      Error(INTERN, &fpos(x), "Manifest: no case for type %s", Image(type(x)));
  2155. X      break;
  2156. X
  2157. X  } /* end switch */
  2158. X
  2159. X  debug2(DOM,D,"]Manifest returning %s %s",Image(type(x)),EchoObject(null, x));
  2160. X  debug1(DOM, DD, "  at exit, style = %s", EchoStyle(style));
  2161. X  debug1(DOM, DDD, "up:    ", EchoObject(null, bthr[COL]) );
  2162. X  debug1(DOM, DDD, "down:  ", EchoObject(null, fthr[COL]) );
  2163. X  debug1(DOM, DDD, "left:  ", EchoObject(null, bthr[ROW]) );
  2164. X  debug1(DOM, DDD, "right: ", EchoObject(null, fthr[ROW]) );
  2165. X  return x;
  2166. X} /* end Manifest */
  2167. END_OF_FILE
  2168.   if test 36495 -ne `wc -c <'lout/z08.c'`; then
  2169.     echo shar: \"'lout/z08.c'\" unpacked with wrong size!
  2170.   fi
  2171.   # end of 'lout/z08.c'
  2172. fi
  2173. echo shar: End of archive 7 \(of 30\).
  2174. cp /dev/null ark7isdone
  2175. MISSING=""
  2176. 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
  2177.     if test ! -f ark${I}isdone ; then
  2178.     MISSING="${MISSING} ${I}"
  2179.     fi
  2180. done
  2181. if test "${MISSING}" = "" ; then
  2182.     echo You have unpacked all 30 archives.
  2183.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2184. else
  2185.     echo You still must unpack the following archives:
  2186.     echo "        " ${MISSING}
  2187. fi
  2188. exit 0
  2189. exit 0 # Just in case...
  2190.