home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume38 / lout / part13 < prev    next >
Encoding:
Text File  |  1993-08-11  |  72.5 KB  |  1,876 lines

  1. Newsgroups: comp.sources.misc
  2. From: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  3. Subject: v38i081:  lout - Lout document formatting system, v2.05, Part13/35
  4. Message-ID: <1993Aug10.032641.17059@sparky.sterling.com>
  5. X-Md4-Signature: f32e568b68d6bd0be32cbccfbce9c9fa
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Tue, 10 Aug 1993 03:26:41 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: jeff@joyce.cs.su.oz.au (Jeff Kingston)
  12. Posting-number: Volume 38, Issue 81
  13. Archive-name: lout/part13
  14. Environment: UNIX
  15. Supersedes: lout: Volume 37, Issue 99-128
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  doc/tr.impl/s5.0 z02.c z15.c z20.c
  22. # Wrapped by kent@sparky on Sun Aug  8 12:29:25 1993
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 13 (of 35)."'
  26. if test -f 'doc/tr.impl/s5.0' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'doc/tr.impl/s5.0'\"
  28. else
  29.   echo shar: Extracting \"'doc/tr.impl/s5.0'\" \(476 characters\)
  30.   sed "s/^X//" >'doc/tr.impl/s5.0' <<'END_OF_FILE'
  31. X@Section
  32. X    @Title { Galleys }
  33. X@Begin
  34. X@PP
  35. XWith objects and definitions under control, the author faced the problem
  36. Xof getting body text, footnotes, floating figures and tables,
  37. Xreferences, index entries, and entries in the table of contents into
  38. Xtheir places.  The resulting investigation occupied three months of
  39. Xfull-time design work, and proceeded approximately as described in
  40. XSection {@NumberOf galleys}; the implementation occupied the years 1987-89.
  41. X@BeginSubSections
  42. END_OF_FILE
  43.   if test 476 -ne `wc -c <'doc/tr.impl/s5.0'`; then
  44.     echo shar: \"'doc/tr.impl/s5.0'\" unpacked with wrong size!
  45.   fi
  46.   # end of 'doc/tr.impl/s5.0'
  47. fi
  48. if test -f 'z02.c' -a "${1}" != "-c" ; then 
  49.   echo shar: Will not clobber existing file \"'z02.c'\"
  50. else
  51.   echo shar: Extracting \"'z02.c'\" \(22154 characters\)
  52.   sed "s/^X//" >'z02.c' <<'END_OF_FILE'
  53. X/*@z02.c:Lexical Analyser:Declarations@***************************************/
  54. X/*                                                                           */
  55. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  56. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  57. X/*                                                                           */
  58. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  59. X/*  Basser Department of Computer Science                                    */
  60. X/*  The University of Sydney 2006                                            */
  61. X/*  AUSTRALIA                                                                */
  62. X/*                                                                           */
  63. X/*  This program is free software; you can redistribute it and/or modify     */
  64. X/*  it under the terms of the GNU General Public License as published by     */
  65. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  66. X/*  any later version.                                                       */
  67. X/*                                                                           */
  68. X/*  This program is distributed in the hope that it will be useful,          */
  69. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  70. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  71. X/*  GNU General Public License for more details.                             */
  72. X/*                                                                           */
  73. X/*  You should have received a copy of the GNU General Public License        */
  74. X/*  along with this program; if not, write to the Free Software              */
  75. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  76. X/*                                                                           */
  77. X/*  FILE:         z02.c                                                      */
  78. X/*  MODULE:       Lexical Analyser                                           */
  79. X/*  EXTERNS:      LexLegalName(), LexInit(), LexPush(), LexPop(),            */
  80. X/*                LexNextTokenPos(), LexGetToken()                           */
  81. X/*                                                                           */
  82. X/*  Implementation note:  this fast and cryptic lexical analyser is adapted  */
  83. X/*  from Waite, W. M.: The Cost of Lexical Analysis, in Software - Practice  */
  84. X/*  and Experience, v16, pp473-488 (May 1986).                               */
  85. X/*                                                                           */
  86. X/*****************************************************************************/
  87. X#include "externs"
  88. X#define    BUFFER_SIZE    8192        /* size of buffer for block read     */
  89. X#define    OTHER        0        /* punctuation or other character    */
  90. X#define    LETTER        1        /* letter type                       */
  91. X#define    QUOTE        2        /* quoted string delimiter type      */
  92. X#define    ESCAPE        3        /* escape character inside strings   */
  93. X#define    COMMENT        4        /* comment delimiter type            */
  94. X#define    CSPACE        5        /* space character type              */
  95. X#define    TAB        6        /* tab character type                */
  96. X#define    NEWLINE        7        /* newline character type            */
  97. X#define    ENDFILE        8        /* end of file character type        */
  98. X
  99. Xstatic    unsigned char    chtbl[256];    /* type table indexed by a FULL_CHAR */
  100. Xstatic    FULL_CHAR    *chpt;        /* pointer to current text character */
  101. Xstatic    FULL_CHAR    *frst;        /* address of first buffer character */
  102. Xstatic    FULL_CHAR    *limit;        /* just past last char in buffer     */
  103. Xstatic    FULL_CHAR    *buf;        /* the character buffer start pos    */
  104. Xstatic    int        blksize;    /* size of block read; others too    */
  105. Xstatic    FULL_CHAR    *startline;    /* position in buff of last newline  */
  106. Xstatic    FILE_NUM    this_file;    /* number of currently open file     */
  107. Xstatic    FILE        *fp;        /* current input file                */
  108. Xstatic    FILE_POS    file_pos;    /* current file position             */
  109. Xstatic    short        ftype;        /* the type of the current file      */
  110. Xstatic    OBJECT        next_token;    /* next token if already read         */
  111. Xstatic    int        offset;        /* where to start reading in file    */
  112. Xstatic    FULL_CHAR    *mem_block;    /* file buffer                       */
  113. X
  114. Xstatic int top_stack;        /* top of lexical analyser stack     */
  115. Xstatic struct {
  116. X  FULL_CHAR    *chpt;        /* pointer to current text character */
  117. X  FULL_CHAR    *frst;        /* address of first buffer character */
  118. X  FULL_CHAR    *limit;        /* just past last char in buffer     */
  119. X  FULL_CHAR    *buf;        /* the character buffer start pos    */
  120. X  int        blksize;    /* size of block read; others too    */
  121. X  FULL_CHAR    *startline;    /* position in buff of last newline  */
  122. X  FILE_NUM    this_file;    /* number of currently open file     */
  123. X  FILE        *fp;        /* current input file                */
  124. X  FILE_POS    file_pos;    /* current file position             */
  125. X  short        ftype;        /* the type of the current file      */
  126. X  OBJECT    next_token;    /* next token if already read         */
  127. X  int        offset;        /* where to start reading in file    */
  128. X  FULL_CHAR    *mem_block;    /* file buffer                       */
  129. X} lex_stack[MAX_LEX_STACK];
  130. X
  131. X/*@::LexLegalName(), LexInit()@***********************************************/
  132. X/*                                                                           */
  133. X/*  BOOLEAN LexLegalName(str)                                                */
  134. X/*                                                                           */
  135. X/*  Check whether str is a valid name for a symbol table entry.              */
  136. X/*  Valid names have the BNF form                                            */
  137. X/*                                                                           */
  138. X/*       <name> ::= <letter>  { <letter> }                                   */
  139. X/*       <name> ::= <special> { <special> }                                  */
  140. X/*       <name> ::= <escape>  { <letter> }                                   */
  141. X/*                                                                           */
  142. X/*  The third form is inaccessible to users and is for internal use only.    */
  143. X/*                                                                           */
  144. X/*****************************************************************************/
  145. X
  146. XBOOLEAN LexLegalName(str)
  147. XFULL_CHAR *str;
  148. X{ int i;  BOOLEAN res;
  149. X  debug1(DLA, DDD, "LexLegalName( %s )", str);
  150. X  switch( chtbl[str[0]] )
  151. X  {
  152. X    case ESCAPE:
  153. X    case LETTER:
  154. X    
  155. X      for( i = 1;  chtbl[str[i]] == LETTER;  i++ );
  156. X      res = str[i] == '\0';
  157. X      break;
  158. X
  159. X
  160. X    case OTHER:
  161. X    
  162. X      for( i = 1;  chtbl[str[i]] == OTHER;  i++ );
  163. X      res = str[i] == '\0';
  164. X      break;
  165. X
  166. X
  167. X    default:
  168. X    
  169. X      res = FALSE;
  170. X      break;
  171. X
  172. X  }
  173. X  debug1(DLA, DDD, "LexLegalName returning %s", bool(res));
  174. X  return res;
  175. X} /* end LexLegalName */
  176. X
  177. X
  178. X/*****************************************************************************/
  179. X/*                                                                           */
  180. X/*  LexInit()                                                                */
  181. X/*                                                                           */
  182. X/*  Initialise character types.  Those not touched are 0 (OTHER).            */
  183. X/*  The function initchtbl() assists in initializing the chtbl.              */
  184. X/*                                                                           */
  185. X/*****************************************************************************/
  186. X
  187. Xstatic initchtbl(val, str)
  188. Xint val;  FULL_CHAR *str;
  189. X{ int i;
  190. X  for( i = 0;  str[i] != '\0';  i++ )
  191. X    chtbl[ str[i] ] = val;
  192. X} /* end initchtbl */
  193. X
  194. XLexInit()
  195. X{ initchtbl(LETTER,  STR_LETTERS_LOWER);
  196. X  initchtbl(LETTER,  STR_LETTERS_UPPER);
  197. X  initchtbl(LETTER,  STR_LETTERS_SYMSTART);
  198. X  initchtbl(LETTER,  STR_LETTERS_EXTRA0);
  199. X  initchtbl(LETTER,  STR_LETTERS_EXTRA1);
  200. X  initchtbl(LETTER,  STR_LETTERS_EXTRA2);
  201. X  initchtbl(LETTER,  STR_LETTERS_EXTRA3);
  202. X  initchtbl(LETTER,  STR_LETTERS_EXTRA4);
  203. X  initchtbl(LETTER,  STR_LETTERS_EXTRA5);
  204. X  initchtbl(LETTER,  STR_LETTERS_EXTRA6);
  205. X  initchtbl(LETTER,  STR_LETTERS_EXTRA7);
  206. X  initchtbl(QUOTE,   STR_QUOTE);
  207. X  initchtbl(ESCAPE,  STR_ESCAPE);
  208. X  initchtbl(COMMENT, STR_COMMENT);
  209. X  initchtbl(CSPACE,  STR_SPACE);
  210. X  initchtbl(TAB,     STR_TAB);
  211. X  initchtbl(NEWLINE, STR_NEWLINE);
  212. X  chtbl['\0'] = ENDFILE;
  213. X} /* end LexInit */
  214. X
  215. X/*@::LexPush(), LexPop()@*****************************************************/
  216. X/*                                                                           */
  217. X/*  LexPush(x, offs, ftype)                                                  */
  218. X/*                                                                           */
  219. X/*  Start reading from the file sequence whose first file is x (subsequent   */
  220. X/*  files are obtained from NextFile).  The first file (x) is to be fseeked  */
  221. X/*  to offs.  When the sequence is done, ftype determines how to continue:   */
  222. X/*                                                                           */
  223. X/*      ftype          action                                                */
  224. X/*                                                                           */
  225. X/*      SOURCE_FILE    last input file ends, return @End \Input              */
  226. X/*      DATABASE_FILE  database file, return @End \Input                     */
  227. X/*      INCLUDE_FILE   include file, must pop lexical analyser and continue  */
  228. X/*                                                                           */
  229. X/*****************************************************************************/
  230. X
  231. XLexPush(x, offs, ftyp)
  232. XFILE_NUM x;  int offs;  int ftyp;
  233. X{ char *malloc();
  234. X  debug3(DLA, D, "LexPush(%s, %d, %s)", FileName(x), offs,
  235. X    ftyp==SOURCE_FILE ? "source" : ftyp==INCLUDE_FILE ? "include" : "database");
  236. X  if( top_stack >= MAX_LEX_STACK - 1 )
  237. X    Error(FATAL, PosOfFile(x), "%s or %s file %s too deeply nested",
  238. X      KW_INCLUDE, KW_DATABASE, FileName(x));
  239. X  if( top_stack >= 0 )  /* save current state */
  240. X  { lex_stack[top_stack].chpt        = chpt;
  241. X    lex_stack[top_stack].frst        = frst;
  242. X    lex_stack[top_stack].limit        = limit;
  243. X    lex_stack[top_stack].buf        = buf;
  244. X    lex_stack[top_stack].blksize    = blksize;
  245. X    lex_stack[top_stack].startline    = startline;
  246. X    lex_stack[top_stack].this_file    = this_file;
  247. X    lex_stack[top_stack].fp        = fp;
  248. X    lex_stack[top_stack].ftype        = ftype;
  249. X    lex_stack[top_stack].next_token    = next_token;
  250. X    lex_stack[top_stack].offset        = offset;
  251. X    lex_stack[top_stack].mem_block    = mem_block;
  252. X    FposCopy( lex_stack[top_stack].file_pos, file_pos );
  253. X  }
  254. X  top_stack += 1;
  255. X  mem_block = (FULL_CHAR *) malloc((MAX_LINE+BUFFER_SIZE+2)*sizeof(FULL_CHAR));
  256. X  if( mem_block == NULL )  Error(FATAL, PosOfFile(x),
  257. X      "run out of memory when opening file %s", FileName(x));
  258. X  buf = chpt = &mem_block[MAX_LINE];
  259. X  this_file = x;  offset = offs;
  260. X  ftype = ftyp;  next_token = nil;
  261. X  *chpt = '\0';  fp = null;
  262. X} /* end LexPush */
  263. X
  264. X
  265. X/*****************************************************************************/
  266. X/*                                                                           */
  267. X/*  LexPop() - pop lexical analyser.                                         */
  268. X/*                                                                           */
  269. X/*****************************************************************************/
  270. X
  271. XLexPop()
  272. X{ debug0(DLA, D, "LexPop()");
  273. X  assert( top_stack > 0, "LexPop: top_stack <= 0!" );
  274. X  if( fp != null )  fclose(fp);
  275. X  top_stack--;
  276. X  free( (char *) mem_block);
  277. X  mem_block    = lex_stack[top_stack].mem_block;
  278. X  chpt         = lex_stack[top_stack].chpt;
  279. X  frst         = lex_stack[top_stack].frst;
  280. X  limit        = lex_stack[top_stack].limit;
  281. X  buf          = lex_stack[top_stack].buf;
  282. X  blksize      = lex_stack[top_stack].blksize;
  283. X  startline    = lex_stack[top_stack].startline;
  284. X  this_file    = lex_stack[top_stack].this_file;
  285. X  fp           = lex_stack[top_stack].fp;
  286. X  ftype        = lex_stack[top_stack].ftype;
  287. X  next_token   = lex_stack[top_stack].next_token;
  288. X  offset       = lex_stack[top_stack].offset;
  289. X  FposCopy( file_pos, lex_stack[top_stack].file_pos );
  290. X} /* end LexPop */
  291. X
  292. X
  293. X/*@::setword(), LexNextTokenPos(), srcnext()@*********************************/
  294. X/*                                                                           */
  295. X/*  setword(typ, res, file_pos, str, len)                                    */
  296. X/*                                                                           */
  297. X/*  Set variable res to a WORD or QWORD token containing string str, etc.    */
  298. X/*                                                                           */
  299. X/*****************************************************************************/
  300. X
  301. X#define setword(typ, res, file_pos, str, len)                \
  302. X{ res = NewWord(typ, len, &file_pos);                    \
  303. X  FposCopy(fpos(res), file_pos);                    \
  304. X  for( c = 0;  c < len;  c++ ) string(res)[c] = str[c];            \
  305. X  string(res)[c] = '\0';                        \
  306. X}
  307. X
  308. X
  309. X/*****************************************************************************/
  310. X/*                                                                           */
  311. X/*  long LexNextTokenPos()                                                   */
  312. X/*                                                                           */
  313. X/*  Equivalent to ftell() on the (buffered) current lex file.                */
  314. X/*                                                                           */
  315. X/*****************************************************************************/
  316. X
  317. Xlong LexNextTokenPos()
  318. X{ long res;
  319. X  if( next_token != nil )
  320. X    Error(FATAL, &fpos(next_token), "illegal macro invokation in database");
  321. X  res = ftell(fp) - (limit - chpt) - (buf - frst);
  322. X  debug1(DLA, D, "LexNextTokenPos() returning %ld", res);
  323. X  return res;
  324. X}
  325. X
  326. X
  327. X/*****************************************************************************/
  328. X/*                                                                           */
  329. X/*  static srcnext()                                                         */
  330. X/*                                                                           */
  331. X/*  Move to new line of input file.  May need to recharge buffer.            */
  332. X/*                                                                           */
  333. X/*****************************************************************************/
  334. X
  335. Xstatic srcnext()
  336. X{ register FULL_CHAR *col;
  337. X  debug4(DLA, DDD, "srcnext();  buf: %d, chpt: %d, frst: %d, limit: %d",
  338. X    buf - mem_block, chpt - mem_block, frst - mem_block, limit - mem_block);
  339. X
  340. X  /* if time to transfer last line to area preceding buffer, do so */
  341. X  if( blksize != 0 && chpt < limit )
  342. X  { debug0(DLA, DDD, "srcnext: transferring.");
  343. X    col = buf;
  344. X    while( (*--col = *--limit) != CH_NEWLINE );
  345. X    frst = col + 1;  limit++;  blksize = 0;
  346. X  }
  347. X
  348. X  /* if buffer is empty, read next block */
  349. X  /*** changed by JK 9/92 from "if( chpt == limit )" to fix long lines bug */
  350. X  if( chpt >= limit )
  351. X  { if( chpt > limit )
  352. X    { col_num(file_pos) = 1;
  353. X      Error(FATAL, &file_pos, "line is too long (or final newline missing)");
  354. X    }
  355. X    chpt = frst;
  356. X    blksize = fread( (char *) buf, sizeof(char), BUFFER_SIZE, fp);
  357. X    debug4(DLA, D, "srcnext: %d = fread(0x%x, %d, %d, fp)",
  358. X      blksize, buf, sizeof(char), BUFFER_SIZE);
  359. X    frst = buf;  limit = buf + blksize;  *limit = CH_NEWLINE;
  360. X  }
  361. X
  362. X  /* if nothing more to read, make this clear */
  363. X  if( chpt >= limit )
  364. X  { debug0(DLA, DDD, "srcnext: nothing more to read");
  365. X    chpt = limit = buf;  *limit = '\0';
  366. X  }
  367. X  debug4(DLA, DDD, "srcnext returning;  buf: %d, chpt: %d, frst: %d, limit: %d",
  368. X    buf - mem_block, chpt - mem_block, frst - mem_block, limit - mem_block);
  369. X} /* end srcnext */
  370. X
  371. X
  372. X/*@::LexGetToken()@***********************************************************/
  373. X/*                                                                           */
  374. X/*  OBJECT LexGetToken()                                                     */
  375. X/*                                                                           */
  376. X/*  Get next token from input.  Look it up in symbol table.                  */
  377. X/*                                                                           */
  378. X/*****************************************************************************/
  379. X
  380. XOBJECT LexGetToken()
  381. X{
  382. X       FULL_CHAR *startpos;        /* where the latest token started    */
  383. X  register FULL_CHAR *p, *q;        /* pointer to current input char     */
  384. X  register int      c;            /* temporary character (really char) */
  385. X  OBJECT   res;                /* result token                      */
  386. X  int vcount, hcount;            /* no. of newlines and spaces seen   */
  387. X
  388. X  if( next_token != nil )
  389. X  { next_token = Delete(res = next_token, PARENT);
  390. X    debug2(DLA, DD, "LexGetToken%s (in macro) returning %s",
  391. X      EchoFilePos(&file_pos), EchoToken(res));
  392. X    return res;
  393. X  }
  394. X
  395. X  res = nil;  p = chpt;
  396. X  vcount = hcount = 0;
  397. X  do switch( chtbl[*p++] )
  398. X  {
  399. X      case ESCAPE:
  400. X      
  401. X    col_num(file_pos) = (startpos = p-1) - startline;
  402. X    Error(WARN, &file_pos, "character %c outside quoted string", *startpos);
  403. X    break;
  404. X
  405. X
  406. X      case COMMENT:
  407. X      
  408. X    debug1(DLA, DDD, "LexGetToken%s: comment", EchoFilePos(&file_pos));
  409. X    while( (c = *p++) != CH_NEWLINE && c != '\0' );
  410. X    --p;
  411. X    break;
  412. X
  413. X
  414. X      case CSPACE:
  415. X
  416. X    hcount++;
  417. X    break;
  418. X
  419. X
  420. X      case TAB:
  421. X
  422. X    hcount += 8;
  423. X    break;
  424. X
  425. X
  426. X      case NEWLINE:
  427. X      
  428. X    chpt = p;  srcnext();
  429. X    line_num(file_pos)++;
  430. X    col_num(file_pos) = 0;
  431. X    vcount++;  hcount = 0;
  432. X    startline = (p = chpt) - 1;
  433. X    break;
  434. X
  435. X
  436. X      case ENDFILE:
  437. X      
  438. X    /* close current file, if any */
  439. X    debug0(DLA, DDD, "LexGetToken: endfile");
  440. X    if( fp != null )
  441. X    { fclose(fp);  fp = null;
  442. X      this_file = ftype == SOURCE_FILE ? NextFile(this_file) : NO_FILE;
  443. X    }
  444. X
  445. X    /* open next file */
  446. X    while( this_file != NO_FILE )
  447. X    { file_num(file_pos) = this_file;
  448. X      line_num(file_pos) = 1;
  449. X      col_num(file_pos) = 0;
  450. X      fp = OpenFile(this_file, FALSE, TRUE);
  451. X      if( fp != null )  break;
  452. X      Error(WARN, &file_pos, "cannot open %s", FileName(this_file));
  453. X      this_file = ftype == SOURCE_FILE ? NextFile(this_file) : NO_FILE;
  454. X    }
  455. X    if( fp != null )
  456. X    { if( offset != 0 )
  457. X      { fseek(fp, (long) offset, 0);
  458. X        offset = 0L;
  459. X      }
  460. X      frst = limit = chpt = buf;
  461. X      blksize = 0;  srcnext();
  462. X      startline = (p = chpt) - 1;
  463. X      hcount = 0;
  464. X    }
  465. X
  466. X    /* no next file, so take continuation */
  467. X    else switch( ftype )
  468. X    {
  469. X      case SOURCE_FILE:
  470. X      case DATABASE_FILE:
  471. X      
  472. X        /* input ends with "@End \Input" */
  473. X        res = NewToken(END, &file_pos, 0, 0, END_PREC, nil);
  474. X        next_token = NewToken(CLOSURE, &file_pos, 0,0, NO_PREC, StartSym);
  475. X        --p;  startline = p;
  476. X        break;
  477. X
  478. X      case INCLUDE_FILE:
  479. X
  480. X        LexPop();
  481. X        (p = chpt) - 1;
  482. X        hcount = 0;
  483. X        break;
  484. X
  485. X      default:  Error(INTERN, no_fpos, "ftype!");
  486. X
  487. X    } /* end switch */
  488. X    break;
  489. X
  490. X
  491. X      case OTHER:
  492. X      
  493. X    col_num(file_pos) = (startpos = p-1) - startline;
  494. X    while( chtbl[*p++] == OTHER );
  495. X    c = p - startpos - 1;
  496. X    do
  497. X    { res = SearchSym(startpos, c);
  498. X      --c; --p;
  499. X    } while( c > 0 && res == nil );
  500. X    goto MORE;  /* 7 lines down */
  501. X    break;
  502. X
  503. X
  504. X      case LETTER:
  505. X      
  506. X    col_num(file_pos) = (startpos = p-1) - startline;
  507. X    while( chtbl[*p++] == LETTER );  --p;
  508. X    res = SearchSym(startpos, p - startpos);
  509. X
  510. X    MORE: if( res == nil )
  511. X    { setword(WORD, res, file_pos, startpos, p-startpos);
  512. X    }
  513. X    else if( type(res) == MACRO )
  514. X    { if( recursive(res) )
  515. X      { Error(WARN, &file_pos, "recursion in macro");
  516. X        setword(WORD, res, file_pos, startpos, p-startpos);
  517. X      }
  518. X      else
  519. X      { res = CopyTokenList( sym_body(res), &file_pos );
  520. X        if( res != nil ) next_token = Delete(res, PARENT);
  521. X        else hcount = 0;
  522. X      }
  523. X    }
  524. X    else if( predefined(res) == 0 )
  525. X    { res = NewToken(CLOSURE, &file_pos, 0, 0, precedence(res), res);
  526. X    }
  527. X    else if( predefined(res) == INCLUDE || predefined(res) == SYS_INCLUDE )
  528. X    { OBJECT t, fname;  FILE_NUM fnum;  int len;
  529. X      chpt = p;
  530. X      t = LexGetToken();
  531. X      if( type(t) != LBR )
  532. X      { Error(WARN, &fpos(t), "%s expected after %s", KW_LBR, SymName(res));
  533. X        Dispose(t);
  534. X        res = nil;
  535. X        break;
  536. X      }
  537. X      fname = Parse(&t, nil, FALSE, FALSE);
  538. X      fname = ReplaceWithTidy(fname);
  539. X      if( !is_word(type(fname)) )
  540. X      { Error(WARN, &fpos(fname), "name of %s file expected here",
  541. X          SymName(res));
  542. X        Dispose(fname);
  543. X        res = nil;
  544. X        break;
  545. X      }
  546. X      len = StringLength(string(fname)) - StringLength(SOURCE_SUFFIX);
  547. X      if( len >= 0 && StringEqual(&string(fname)[len], SOURCE_SUFFIX) )
  548. X        StringCopy(&string(fname)[len], STR_EMPTY);
  549. X      fnum = DefineFile(string(fname), STR_EMPTY, &fpos(fname),
  550. X          INCLUDE_FILE,
  551. X          predefined(res)==INCLUDE ? INCLUDE_PATH : SYSINCLUDE_PATH);
  552. X      Dispose(fname);
  553. X      LexPush(fnum, 0, INCLUDE_FILE);
  554. X      res = LexGetToken();
  555. X      p = chpt;
  556. X    }
  557. X    else res = NewToken(predefined(res), &file_pos,0,0,precedence(res),res);
  558. X    break;
  559. X
  560. X
  561. X      case QUOTE:
  562. X      
  563. X    col_num(file_pos) = (startpos = q = p) - 1 - startline;
  564. X    do switch( chtbl[*q++ = *p++] )
  565. X    {
  566. X      case OTHER:
  567. X      case LETTER:
  568. X      case COMMENT:
  569. X      case CSPACE:
  570. X      case TAB:    break;
  571. X
  572. X      case NEWLINE:
  573. X      case ENDFILE:    --p;
  574. X            Error(WARN, &file_pos, "unterminated string");
  575. X            setword(QWORD, res, file_pos, startpos, q-1-startpos);
  576. X            break;
  577. X
  578. X      case QUOTE:    setword(QWORD, res, file_pos, startpos, q-1-startpos);
  579. X            break;
  580. X
  581. X      case ESCAPE:    q--;
  582. X            if( chtbl[*p] == NEWLINE || chtbl[*p] == ENDFILE )
  583. X            { Error(WARN, &file_pos, "unterminated string");
  584. X              setword(QWORD, res, file_pos, startpos, q-startpos);
  585. X            }
  586. X            else if( octaldigit(*p) )
  587. X            { int count, ch;
  588. X              count = ch = 0;
  589. X              do
  590. X              { ch = ch * 8 + digitchartonum(*p++);
  591. X                count++;
  592. X              } while( octaldigit(*p) && count < 3 );
  593. X              if( ch == '\0' )  Error(WARN, &file_pos,
  594. X                "skipping null character \0 in string");
  595. X              else *q++ = ch;
  596. X            }
  597. X            else *q++ = *p++;
  598. X            break;
  599. X
  600. X      default:    Error(INTERN, &file_pos, "LexGetToken: quoted string");
  601. X            break;
  602. X
  603. X    } while( res == nil );
  604. X    break;
  605. X
  606. X
  607. X      default:
  608. X      
  609. X    Error(INTERN, &file_pos, "LexGetToken: bad chtbl[]");
  610. X    break;
  611. X
  612. X  } while( res == nil );
  613. X
  614. X  if( p - startline >= MAX_LINE )
  615. X  { col_num(file_pos) = 1;
  616. X    Error(FATAL, &file_pos, "line is too long (or final newline missing)");
  617. X  }
  618. X
  619. X  chpt = p;
  620. X  vspace(res) = vcount;
  621. X  hspace(res) = hcount;
  622. X  debug4(DLA, DD, "LexGetToken%s returning %s %s (@%d)",
  623. X    EchoFilePos(&file_pos), Image(type(res)), EchoToken(res), (int) res);
  624. X  return res;
  625. X} /* end LexGetToken */
  626. END_OF_FILE
  627.   if test 22154 -ne `wc -c <'z02.c'`; then
  628.     echo shar: \"'z02.c'\" unpacked with wrong size!
  629.   fi
  630.   # end of 'z02.c'
  631. fi
  632. if test -f 'z15.c' -a "${1}" != "-c" ; then 
  633.   echo shar: Will not clobber existing file \"'z15.c'\"
  634. else
  635.   echo shar: Extracting \"'z15.c'\" \(23939 characters\)
  636.   sed "s/^X//" >'z15.c' <<'END_OF_FILE'
  637. X/*@z15.c:Size Constraints:MinConstraint(), EnlargeToConstraint()@*************/
  638. X/*                                                                           */
  639. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  640. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  641. X/*                                                                           */
  642. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  643. X/*  Basser Department of Computer Science                                    */
  644. X/*  The University of Sydney 2006                                            */
  645. X/*  AUSTRALIA                                                                */
  646. X/*                                                                           */
  647. X/*  This program is free software; you can redistribute it and/or modify     */
  648. X/*  it under the terms of the GNU General Public License as published by     */
  649. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  650. X/*  any later version.                                                       */
  651. X/*                                                                           */
  652. X/*  This program is distributed in the hope that it will be useful,          */
  653. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  654. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  655. X/*  GNU General Public License for more details.                             */
  656. X/*                                                                           */
  657. X/*  You should have received a copy of the GNU General Public License        */
  658. X/*  along with this program; if not, write to the Free Software              */
  659. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  660. X/*                                                                           */
  661. X/*  FILE:         z15.c                                                      */
  662. X/*  MODULE:       Size Constraints                                           */
  663. X/*  EXTERNS:      MinConstraint(), EnlargeToConstraint(),                    */
  664. X/*                ReflectConstraint(), SemiRotateConstraint(),               */
  665. X/*                RotateConstraint(), InvScaleConstraint(), Constrained(),   */
  666. X/*                EchoConstraint(), DebugConstrained()                       */
  667. X/*                                                                           */
  668. X/*****************************************************************************/
  669. X#include <math.h>
  670. X#ifndef M_PI
  671. X#define M_PI       3.1415926535897931160E0
  672. X#endif
  673. X
  674. X#include "externs"
  675. X
  676. X
  677. X/*****************************************************************************/
  678. X/*                                                                           */
  679. X/*  MinConstraint(xc, yc)                                                    */
  680. X/*                                                                           */
  681. X/*  Replace *xc by the minimum of the two constraints *xc and *yc.           */
  682. X/*                                                                           */
  683. X/*****************************************************************************/
  684. X
  685. XMinConstraint(xc, yc)
  686. XCONSTRAINT *xc, *yc;
  687. X{ bc(*xc)  = min(bc(*xc),  bc(*yc));
  688. X  bfc(*xc) = min(bfc(*xc), bfc(*yc));
  689. X  fc(*xc)  = min(fc(*xc),  fc(*yc));
  690. X} /* end MinConstraint */
  691. X
  692. X
  693. X/*****************************************************************************/
  694. X/*                                                                           */
  695. X/*  EnlargeToConstraint(b, f, c)                                             */
  696. X/*                                                                           */
  697. X/*  Enlarge *b,*f to its largest possible value within constraint *c.        */
  698. X/*                                                                           */
  699. X/*****************************************************************************/
  700. X
  701. XEnlargeToConstraint(b, f, c)
  702. XLENGTH *b, *f;  CONSTRAINT *c;
  703. X{
  704. X  *f = min(bfc(*c) - *b, fc(*c));
  705. X} /* end EnlargeToConstraint */
  706. X
  707. X
  708. X/*@::InvScaleConstraint(), ReflectConstraint(), etc.@*************************/
  709. X/*                                                                           */
  710. X/*  InvScaleConstraint(yc, sf, xc)                                           */
  711. X/*                                                                           */
  712. X/*  Scale constraint xc to the inverse of the scale factor sf.               */
  713. X/*                                                                           */
  714. X/*****************************************************************************/
  715. X
  716. XInvScaleConstraint(yc, sf, xc)
  717. XCONSTRAINT *yc;  LENGTH sf;  CONSTRAINT *xc;
  718. X{ char buff[10];
  719. X  ifdebug(DSC, D, sprintf(buff, "%.3f", (float) sf / SF));
  720. X  debug2(DSC, D, "InvScaleConstraint(yc, %s, %s)", buff, EchoConstraint(xc));
  721. X  assert( sf > 0, "InvScaleConstraint: sf <= 0!" );
  722. X  bc(*yc)  = bc(*xc)  == MAX_LEN ? MAX_LEN : min(MAX_LEN, bc(*xc)  * SF / sf);
  723. X  bfc(*yc) = bfc(*xc) == MAX_LEN ? MAX_LEN : min(MAX_LEN, bfc(*xc) * SF / sf);
  724. X  fc(*yc)  = fc(*xc)  == MAX_LEN ? MAX_LEN : min(MAX_LEN, fc(*xc)  * SF / sf);
  725. X  debug1(DSC, D, "InvScaleConstraint returning %s", EchoConstraint(yc));
  726. X} /* end InvScaleConstraint */
  727. X
  728. X
  729. X/*****************************************************************************/
  730. X/*                                                                           */
  731. X/*  ReflectConstraint(xc, yc)                                                */
  732. X/*                                                                           */
  733. X/*  Set xc to the constraint which is yc with its back and forward reversed. */
  734. X/*                                                                           */
  735. X/*****************************************************************************/
  736. X
  737. X#define ReflectConstraint(xc, yc)  SetConstraint(xc, fc(yc), bfc(yc), bc(yc))
  738. X
  739. X
  740. X/*****************************************************************************/
  741. X/*                                                                           */
  742. X/*  static SemiRotateConstraint(xc, u, v, angle, yc)                         */
  743. X/*                                                                           */
  744. X/*  Used by RotateConstraint to calculate one rotated constraint.            */
  745. X/*                                                                           */
  746. X/*****************************************************************************/
  747. X
  748. Xstatic SemiRotateConstraint(xc, u, v, angle, yc)
  749. XCONSTRAINT *xc;  LENGTH u, v;  float angle; CONSTRAINT *yc;
  750. X{ float cs, sn;  char buff[20];
  751. X  ifdebug(DSC, D, sprintf(buff, "%.1f", angle * 360.0 / (2 * M_PI)));
  752. X  debug4(DSC, D, "SemiRotateConstraint(xc, %s, %s, %sd, %s",
  753. X    EchoLength(u), EchoLength(v), buff, EchoConstraint(yc));
  754. X  cs = cos(angle);  sn = sin(angle);
  755. X  if( fabs(cs) < 1e-6 )
  756. X    SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  757. X  else
  758. X    SetConstraint(*xc,
  759. X      min(MAX_LEN, (bc(*yc) - u * sn) / cs),
  760. X      min(MAX_LEN, (bfc(*yc) - u * sn - v * sn) / cs),
  761. X      min(MAX_LEN, (fc(*yc) - v * sn) / cs) );
  762. X  debug1(DSC, D, "SemiRotateConstraint returning %s", EchoConstraint(xc));
  763. X} /* end SemiRotateConstraint */
  764. X
  765. X
  766. X/*@::RotateConstraint()@******************************************************/
  767. X/*                                                                           */
  768. X/*  RotateConstraint(c, y, angle, hc, vc, dim)                               */
  769. X/*                                                                           */
  770. X/*  Take the object angle @Rotate y, which is supposed to be constrained     */
  771. X/*  horizontally by hc and vertically by vc, and determine a constraint      */
  772. X/*  (either horizontal or vertical, depending on dim) for y.                 */
  773. X/*                                                                           */
  774. X/*  The constraint returned is a trigonometric function of all these         */
  775. X/*  parameters, including the present size of y in dimension 1-dim.          */
  776. X/*                                                                           */
  777. X/*****************************************************************************/
  778. X
  779. XRotateConstraint(c, y, angle, hc, vc, dim)
  780. XCONSTRAINT *c;  OBJECT y;  LENGTH angle;  CONSTRAINT *hc, *vc;  int dim;
  781. X{ CONSTRAINT c1, c2, c3, dc;  float theta, psi;
  782. X  char buff[20];
  783. X  ifdebug(DSC, D, sprintf(buff, "%.1f", (float) angle / DG ));
  784. X  debug4(DSC, D, "RotateConstraint(c, y, %sd, %s, %s, %s)",
  785. X    buff, EchoConstraint(hc), EchoConstraint(vc), dimen(dim));
  786. X
  787. X  /* work out angle in radians between 0 and 2*PI */
  788. X  theta = (float) angle * 2 * M_PI / (float) (DG * 360);
  789. X  while( theta < 0 ) theta += 2 * M_PI;
  790. X  while( theta >= 2 * M_PI ) theta -= 2 * M_PI;
  791. X  assert( 0 <= theta && theta <= 2 * M_PI, "RotateConstraint: theta!" );
  792. X
  793. X  /* determine theta, c1, and c2 depending on which quadrant we are in */
  794. X  if( theta <= M_PI / 2.0 )   /* first quadrant */
  795. X  { theta = theta;
  796. X    CopyConstraint(c1, *hc);
  797. X    CopyConstraint(c2, *vc);
  798. X  }
  799. X  else if ( theta <= M_PI )   /* second quadrant */
  800. X  { theta -= M_PI / 2.0;
  801. X    ReflectConstraint(c1, *vc);
  802. X    CopyConstraint(c2, *hc);
  803. X  }
  804. X  else if ( theta <= 3.0 * M_PI / 2.0 )   /* third quadrant */
  805. X  { theta -= M_PI;
  806. X    ReflectConstraint(c1, *hc);
  807. X    ReflectConstraint(c2, *vc);
  808. X  }
  809. X  else /* fourth quadrant */
  810. X  { theta -= 3.0 * M_PI / 2.0;
  811. X    CopyConstraint(c1, *vc);
  812. X    ReflectConstraint(c2, *hc);
  813. X  }
  814. X  psi = M_PI / 2.0 - theta;
  815. X  debug2(DSC, D, "  c1: %s;  c2: %s", EchoConstraint(&c1), EchoConstraint(&c2));
  816. X
  817. X  /* return the minimum of the two constraints, rotated */
  818. X  if( dim == COL )
  819. X  { SemiRotateConstraint(c, back(y, ROW), fwd(y, ROW), theta, &c1);
  820. X    ReflectConstraint(c3, c2);
  821. X    SemiRotateConstraint(&dc, fwd(y, ROW), back(y, ROW), psi, &c3);
  822. X    MinConstraint(c, &dc);
  823. X  }
  824. X  else
  825. X  { SemiRotateConstraint(c, back(y, COL), fwd(y, COL), psi, &c1);
  826. X    SemiRotateConstraint(&dc, fwd(y, COL), back(y, COL), theta, &c2);
  827. X    MinConstraint(c, &dc);
  828. X  }
  829. X
  830. X  debug1(DSC, D, "RotateConstraint returning %s", EchoConstraint(c));
  831. X} /* end RotateConstraint */
  832. X
  833. X
  834. X/*@::CatConstrained()@********************************************************/
  835. X/*                                                                           */
  836. X/*  static CatConstrained(x, xc, ratm, y, dim)                               */
  837. X/*                                                                           */
  838. X/*  Calculate the size constraint of object x, as for Constrained below.     */
  839. X/*  y is the enclosing VCAT etc. object;  ratm is TRUE if a ^ lies after     */
  840. X/*  x anywhere.  dim is COL or ROW.                                          */
  841. X/*                                                                           */
  842. X/*  The meaning of the key variables is as follows:                          */
  843. X/*                                                                           */
  844. X/*  be       The amount by which back(x, dim) can increase from zero         */
  845. X/*           without having any impact on size(y, dim).  Thereafter,         */
  846. X/*           any increase causes an equal increase in size(y, dim).          */
  847. X/*                                                                           */
  848. X/*  fe       The amount by which fwd(x, dim) can increase from zero          */
  849. X/*           without having any impact on size(y, dim).  Thereafter,         */
  850. X/*           any increase causes an equal increase in size(y, dim).          */
  851. X/*                                                                           */
  852. X/*  backy,   The value that back(y, dim) and fwd(y, dim) would have if x     */
  853. X/*  fwdy     was definite with size 0,0.  They will in general be larger     */
  854. X/*           than the present values if x is indefinite, and smaller         */
  855. X/*           if x is definite, although it depends on marks and gaps.        */
  856. X/*                                                                           */
  857. X/*****************************************************************************/
  858. X
  859. Xstatic CatConstrained(x, xc, ratm, y, dim)
  860. XOBJECT x;  CONSTRAINT *xc; BOOLEAN ratm;  OBJECT y;  int dim;
  861. X{ int side;            /* the size of y that x is on: BACK, ON, FWD */
  862. X  CONSTRAINT yc;        /* constraints on y                          */
  863. X  LENGTH backy, fwdy;        /* back(y), fwd(y) would be if x was (0, 0)  */
  864. X  LENGTH be, fe;        /* amount back(x), fwd(x) can be for free    */
  865. X  LENGTH beffect, feffect;    /* scratch variables for calculations        */
  866. X  LENGTH seffect;        /* scratch variables for calculations        */
  867. X  OBJECT link, sg, pg;    /* link to x, its successor and predecessor  */
  868. X  OBJECT prec_def, sd;    /* definite object preceding (succeeding) x  */
  869. X  int tb, tbf, tf, tbc, tbfc, tfc, mxy, myz;
  870. X
  871. X  Constrained(y, &yc, dim);
  872. X  if( constrained(yc) )
  873. X  {
  874. X    /* find the link of x, and its neighbours and their links */
  875. X    link = UpDim(x, dim);
  876. X    SetNeighbours(link, ratm, &pg, &prec_def, &sg, &sd, &side);
  877. X
  878. X    /* amount of space available at x without changing the size of y */
  879. X    be = pg == nil ? 0 : ExtraGap(fwd(prec_def, dim), 0, &gap(pg), BACK);
  880. X    fe = sg == nil ? 0 : ExtraGap(0, back(sd, dim),      &gap(sg), FWD);
  881. X
  882. X    if( is_indefinite(type(x)) )
  883. X    {
  884. X      /* insert two lengths and delete one */
  885. X      beffect = pg == nil ? 0 : MinGap(fwd(prec_def, dim), 0, 0, &gap(pg));
  886. X      feffect = sg == nil ? 0 : MinGap(0, back(sd,dim), fwd(sd,dim), &gap(sg));
  887. X      seffect = pg == nil ?
  888. X      sg == nil ? 0 : back(sd, dim) :
  889. X      sg == nil ? fwd(prec_def, dim) :
  890. X        MinGap(fwd(prec_def, dim), back(sd, dim), fwd(sd, dim), &gap(sg));
  891. X
  892. X      switch( side )
  893. X      {
  894. X    case BACK:    backy = back(y, dim) + beffect + feffect - seffect;
  895. X            fwdy  = fwd(y, dim);
  896. X            break;
  897. X
  898. X    case ON:    /* must be first, other cases prohibited */
  899. X            backy = 0;
  900. X            fwdy = fwd(y, dim) + feffect;
  901. X            break;
  902. X
  903. X    case FWD:    backy = back(y, dim);
  904. X            fwdy  = fwd(y, dim) + beffect + feffect - seffect;
  905. X            break;
  906. X      }
  907. X    }
  908. X
  909. X    else /* x is definite */
  910. X
  911. X    { beffect = pg == nil ? back(x, dim) :
  912. X    MinGap(fwd(prec_def, dim), back(x,dim), fwd(x,dim), &gap(pg)) -
  913. X    MinGap(fwd(prec_def, dim), 0,           0,          &gap(pg));
  914. X
  915. X      feffect = sg == nil ? fwd(x, dim) :
  916. X    MinGap(fwd(x, dim), back(sd, dim), fwd(sd, dim), &gap(sg)) -
  917. X    MinGap(0,           back(sd, dim), fwd(sd, dim), &gap(sg));
  918. X
  919. X      switch( side )
  920. X      {
  921. X    case BACK:    backy = back(y, dim) - beffect - feffect;
  922. X            fwdy  = fwd(y, dim);
  923. X            break;
  924. X
  925. X    case ON:    backy = back(y, dim) - beffect;
  926. X            fwdy  = fwd(y, dim)  - feffect;
  927. X            break;
  928. X
  929. X    case FWD:    backy = back(y, dim);
  930. X            fwdy  = fwd(y, dim) - beffect - feffect;
  931. X            break;
  932. X      }
  933. X    }
  934. X
  935. X    debug5(DSC, DDD, "side: %s, backy: %s, fwdy: %s, be: %s, fe: %s",
  936. X        Image(side), EchoLength(backy), EchoLength(fwdy),
  937. X        EchoLength(be), EchoLength(fe) );
  938. X
  939. X    if( !FitsConstraint(backy, fwdy, yc) )
  940. X      SetConstraint(*xc, -1, -1, -1);
  941. X    else switch( side )
  942. X    {
  943. X
  944. X      case BACK:
  945. X    
  946. X    tbc = bc(yc) == MAX_LEN ? MAX_LEN : bc(yc) - backy;
  947. X    tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
  948. X    mxy = min(tbc, tbfc);
  949. X    tb  = min(MAX_LEN, be + mxy);
  950. X    tbf = min(MAX_LEN, be + fe + mxy);
  951. X    tf  = min(MAX_LEN, fe + mxy);
  952. X    SetConstraint(*xc, tb, tbf, tf);
  953. X    break;
  954. X
  955. X
  956. X      case ON:
  957. X    
  958. X    tbc = bc(yc) == MAX_LEN ? MAX_LEN : bc(yc) - backy;
  959. X    tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
  960. X    tfc = fc(yc) == MAX_LEN ? MAX_LEN : fc(yc) - fwdy;
  961. X    mxy = min(tbc, tbfc);
  962. X    myz = min(tfc, tbfc);
  963. X    tb  = min(MAX_LEN, be + mxy);
  964. X    tbf = min(MAX_LEN, be + fe + tbfc);
  965. X    tf  = min(MAX_LEN, fe + myz);
  966. X    SetConstraint(*xc, tb, tbf, tf);
  967. X    break;
  968. X    
  969. X
  970. X      case FWD:
  971. X
  972. X    tfc = fc(yc) == MAX_LEN ? MAX_LEN : fc(yc) - fwdy;
  973. X    tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
  974. X    mxy = min(tfc, tbfc);
  975. X    tb  = min(MAX_LEN, be + mxy);
  976. X    tbf = min(MAX_LEN, be + fe + mxy);
  977. X    tf  = min(MAX_LEN, fe + mxy);
  978. X    SetConstraint(*xc, tb, tbf, tf);
  979. X    break;
  980. X    
  981. X    }
  982. X  } /* end if( constrained ) */
  983. X  else SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  984. X} /* end CatConstrained */
  985. X
  986. X
  987. X/*@::Constrained()@***********************************************************/
  988. X/*                                                                           */
  989. X/*  Constrained(x, xc, dim)                                                  */
  990. X/*                                                                           */
  991. X/*  Calculate the size constraint of object x, and return it in *xc.         */
  992. X/*                                                                           */
  993. X/*****************************************************************************/
  994. X
  995. XConstrained(x, xc, dim)
  996. XOBJECT x;  CONSTRAINT *xc;  int dim;
  997. X{ OBJECT y, link, lp, rp, z, tlink, g;  CONSTRAINT yc, hc, vc;
  998. X  BOOLEAN ratm;  LENGTH xback, xfwd;  int tb, tf, tbf, tbc, tfc;
  999. X  debug2(DSC, DD, "[ Constrained( %s, xc, %s )", EchoObject(x), dimen(dim));
  1000. X  assert( Up(x) != x, "Constrained: x has no parent!" );
  1001. X
  1002. X  /* find y, the parent of x */
  1003. X  link = UpDim(x, dim);  ratm = FALSE;
  1004. X  for( tlink = NextDown(link);  type(tlink) == LINK;  tlink = NextDown(tlink) )
  1005. X  { Child(g, tlink);
  1006. X    if( type(g) == GAP_OBJ && mark(gap(g)) )  ratm = TRUE;
  1007. X  }
  1008. X  y = tlink;
  1009. X  debug1(DSC, DDD, "parent y = %s", Image(type(y)));
  1010. X  ifdebug(DSC, DDD, DebugObject(y));
  1011. X
  1012. X  switch( type(y) )
  1013. X  {
  1014. X    case GRAPHIC:
  1015. X    case ONE_COL:
  1016. X    case ONE_ROW:
  1017. X    case HCONTRACT:
  1018. X    case VCONTRACT:
  1019. X    case HEXPAND:
  1020. X    case VEXPAND:
  1021. X    case PADJUST:
  1022. X    case HADJUST:
  1023. X    case VADJUST:
  1024. X    case SPLIT:
  1025. X    
  1026. X      Constrained(y, xc, dim);
  1027. X      break;
  1028. X
  1029. X
  1030. X    case VSCALE:
  1031. X    case HSCALE:
  1032. X    
  1033. X      if( (dim == COL) != (type(y) == HSCALE) )  Constrained(y, xc, dim);
  1034. X      else SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  1035. X      break;
  1036. X
  1037. X
  1038. X    case SCALE:
  1039. X
  1040. X      Constrained(y, &yc, dim);
  1041. X      InvScaleConstraint(xc,
  1042. X    dim == COL ? bc(constraint(y)) : fc(constraint(y)), &yc);
  1043. X      break;
  1044. X
  1045. X
  1046. X    case ROTATE:
  1047. X    
  1048. X      Constrained(y, &hc, COL);  Constrained(y, &vc, ROW);
  1049. X      RotateConstraint(xc, x, sparec(constraint(y)), &hc, &vc, dim);
  1050. X      break;
  1051. X
  1052. X
  1053. X    case WIDE:
  1054. X    case HIGH:
  1055. X    
  1056. X      Constrained(y, xc, dim);
  1057. X      if( (type(y)==WIDE) == (dim==COL) )  MinConstraint(xc, &constraint(y));
  1058. X      break;
  1059. X
  1060. X
  1061. X    case HEAD:
  1062. X    
  1063. X      if( dim == ROW ) SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  1064. X      else
  1065. X      {    CopyConstraint(yc, constraint(y));
  1066. X    debug1(DSC, DD, "  head: %s; val is:", EchoConstraint(&yc));
  1067. X    ifdebug(DSC, DD, DebugObject(y));
  1068. X    goto REST_OF_HEAD;   /* a few lines down */
  1069. X      }
  1070. X      break;
  1071. X
  1072. X
  1073. X    case COL_THR:
  1074. X    case ROW_THR:
  1075. X
  1076. X      assert( (type(y)==COL_THR) == (dim==COL), "Constrained: COL_THR!" );
  1077. X      Constrained(y, &yc, dim);
  1078. X      tb = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - fwd(y, dim);
  1079. X      tb = min(bc(yc), tb);
  1080. X      tf = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - back(y, dim);
  1081. X      tf = min(fc(yc), tf);
  1082. X      SetConstraint(*xc, tb, bfc(yc), tf);
  1083. X      break;
  1084. X
  1085. X
  1086. X    case VCAT:
  1087. X    case HCAT:
  1088. X    case ACAT:
  1089. X    
  1090. X      if( (type(y)==VCAT) == (dim==ROW) )
  1091. X      {    CatConstrained(x, xc, ratm, y, dim);
  1092. X    break;
  1093. X      }
  1094. X      Constrained(y, &yc, dim);
  1095. X      if( !constrained(yc) )  SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  1096. X      else
  1097. X      {
  1098. X    REST_OF_HEAD:
  1099. X    /* let lp and rp be the links of the gaps delimiting */
  1100. X    /* the components joined to x (or parent if no such) */
  1101. X    for( lp = PrevDown(link);  lp != y;  lp = PrevDown(lp) )
  1102. X    { Child(z, lp);
  1103. X      if( type(z) == GAP_OBJ && !join(gap(z)) )  break;
  1104. X    }
  1105. X    for( rp = NextDown(link);  rp != y;  rp = NextDown(rp) )
  1106. X    { Child(z, rp);
  1107. X      if( type(z) == GAP_OBJ && !join(gap(z)) )  break;
  1108. X    }
  1109. X    if( lp == y && rp == y && !(type(y) == HEAD && seen_nojoin(y)) )
  1110. X    {
  1111. X      /* if whole object is joined, do this */
  1112. X          tb = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - fwd(y, dim);
  1113. X          tb = min(bc(yc), tb);
  1114. X          tf = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - back(y, dim);
  1115. X          tf = min(fc(yc), tf);
  1116. X          SetConstraint(*xc, tb, bfc(yc), tf);
  1117. X    }
  1118. X    else
  1119. X    {
  1120. X      /* if // or || is present, do this */
  1121. X      xback = xfwd = 0;
  1122. X      for(link = NextDown(lp); link != rp;  link = NextDown(link) )
  1123. X      { Child(z, link);
  1124. X        if( type(z) == GAP_OBJ || is_index(type(z)) )  continue;
  1125. X        xback = max(xback, back(z, dim));  xfwd = max(xfwd, fwd(z, dim));
  1126. X      }
  1127. X      debug2(DSC, DD, "  lp != rp; xback,xfwd = %s,%s",
  1128. X            EchoLength(xback), EchoLength(xfwd));
  1129. X      tbf = min(bfc(yc), fc(yc));
  1130. X      tbc = tbf == MAX_LEN ? MAX_LEN : tbf - xfwd;
  1131. X      tfc = tbf == MAX_LEN ? MAX_LEN : tbf - xback;
  1132. X      SetConstraint(*xc, tbc, tbf, tfc);
  1133. X    }
  1134. X      }
  1135. X      break;
  1136. X
  1137. X
  1138. X    default:  Error(INTERN, &fpos(y), "Constrained: %s", Image(type(y)) );
  1139. X          break;
  1140. X  }
  1141. X  debug1(DSC, DD, "] Constrained returning %s", EchoConstraint(xc));
  1142. X} /* end Constrained */
  1143. X
  1144. X
  1145. X/*@::EchoConstraint(), DebugConstrained()@************************************/
  1146. X/*                                                                           */
  1147. X/*  FULL_CHAR *EchoConstraint(c)                                             */
  1148. X/*                                                                           */
  1149. X/*  Returns a string showing constraint *c, in centimetres.                  */
  1150. X/*                                                                           */
  1151. X/*****************************************************************************/
  1152. X#if DEBUG_ON
  1153. X
  1154. XFULL_CHAR *EchoConstraint(c)
  1155. XCONSTRAINT *c;
  1156. X{ static char str[2][40];
  1157. X  static int i = 0;
  1158. X  i = (i+1) % 2;
  1159. X  sprintf(str[i], "<");
  1160. X  if( bc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF, ");
  1161. X  else sprintf(&str[i][strlen(str[i])], "%.3fc, ", (float) bc(*c)/CM);
  1162. X  if( bfc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF, ");
  1163. X  else sprintf(&str[i][strlen(str[i])], "%.3fc, ", (float) bfc(*c)/CM);
  1164. X  if( fc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF>");
  1165. X  else sprintf(&str[i][strlen(str[i])], "%.3fc>", (float) fc(*c)/CM);
  1166. X  return AsciiToFull(str[i]);
  1167. X} /* end EchoConstraint */
  1168. X
  1169. X
  1170. X/*****************************************************************************/
  1171. X/*                                                                           */
  1172. X/*  DebugConstrained(x)                                                      */
  1173. X/*                                                                           */
  1174. X/*  Calculate and print the constraints of all closures lying within         */
  1175. X/*  sized object x.                                                          */
  1176. X/*                                                                           */
  1177. X/*****************************************************************************/
  1178. X
  1179. XDebugConstrained(x)
  1180. XOBJECT x;
  1181. X{ OBJECT y, link;
  1182. X  CONSTRAINT c;
  1183. X  debug1(DSC, DDD, "DebugConstrained( %s )", EchoObject(x) );
  1184. X  switch( type(x) )
  1185. X  {
  1186. X
  1187. X    case CROSS:
  1188. X    case ROTATE:
  1189. X    case INCGRAPHIC:
  1190. X    case SINCGRAPHIC:
  1191. X    case GRAPHIC:
  1192. X    case WORD:
  1193. X    case QWORD:
  1194. X    
  1195. X      break;
  1196. X
  1197. X
  1198. X    case CLOSURE:
  1199. X    
  1200. X      Constrained(x, &c, COL);
  1201. X      debug2(DSC, D, "Constrained( %s, &c, COL ) = %s",
  1202. X    EchoObject(x), EchoConstraint(&c));
  1203. X      Constrained(x, &c, ROW);
  1204. X      debug2(DSC, D, "Constrained( %s, &c, ROW ) = %s",
  1205. X    EchoObject(x), EchoConstraint(&c));
  1206. X      break;
  1207. X
  1208. X
  1209. X    case SPLIT:
  1210. X    
  1211. X      link = DownDim(x, COL);  Child(y, link);
  1212. X      DebugConstrained(y);
  1213. X      break;
  1214. X
  1215. X
  1216. X    case HEAD:
  1217. X    case ONE_COL:
  1218. X    case ONE_ROW:
  1219. X    case HCONTRACT:
  1220. X    case VCONTRACT:
  1221. X    case HEXPAND:
  1222. X    case VEXPAND:
  1223. X    case PADJUST:
  1224. X    case HADJUST:
  1225. X    case VADJUST:
  1226. X    case HSCALE:
  1227. X    case VSCALE:
  1228. X    case SCALE:
  1229. X    case WIDE:
  1230. X    case HIGH:
  1231. X    
  1232. X      link = Down(x);  Child(y, link);
  1233. X      DebugConstrained(y);
  1234. X      break;
  1235. X
  1236. X
  1237. X    case COL_THR:
  1238. X    case VCAT:
  1239. X    case HCAT:
  1240. X    case ACAT:
  1241. X    
  1242. X      for( link = Down(x);  link != x;  link =NextDown(link) )
  1243. X      {    Child(y, link);
  1244. X    if( type(y) != GAP_OBJ && !is_index(type(y)) )  DebugConstrained(y);
  1245. X      }
  1246. X      break;
  1247. X
  1248. X
  1249. X    default:
  1250. X    
  1251. X      Error(INTERN, &fpos(x), "DebugConstrained: type(x)= %s", Image(type(x)) );
  1252. X      break;
  1253. X
  1254. X  }
  1255. X  debug0(DSC, DDD, "DebugConstrained returning.");
  1256. X} /* end DebugConstrained */
  1257. X#endif
  1258. END_OF_FILE
  1259.   if test 23939 -ne `wc -c <'z15.c'`; then
  1260.     echo shar: \"'z15.c'\" unpacked with wrong size!
  1261.   fi
  1262.   # end of 'z15.c'
  1263. fi
  1264. if test -f 'z20.c' -a "${1}" != "-c" ; then 
  1265.   echo shar: Will not clobber existing file \"'z20.c'\"
  1266. else
  1267.   echo shar: Extracting \"'z20.c'\" \(22867 characters\)
  1268.   sed "s/^X//" >'z20.c' <<'END_OF_FILE'
  1269. X/*@z20.c:Galley Flushing:ParentFlush()@***************************************/
  1270. X/*                                                                           */
  1271. X/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  1272. X/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  1273. X/*                                                                           */
  1274. X/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  1275. X/*  Basser Department of Computer Science                                    */
  1276. X/*  The University of Sydney 2006                                            */
  1277. X/*  AUSTRALIA                                                                */
  1278. X/*                                                                           */
  1279. X/*  This program is free software; you can redistribute it and/or modify     */
  1280. X/*  it under the terms of the GNU General Public License as published by     */
  1281. X/*  the Free Software Foundation; either version 1, or (at your option)      */
  1282. X/*  any later version.                                                       */
  1283. X/*                                                                           */
  1284. X/*  This program is distributed in the hope that it will be useful,          */
  1285. X/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  1286. X/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  1287. X/*  GNU General Public License for more details.                             */
  1288. X/*                                                                           */
  1289. X/*  You should have received a copy of the GNU General Public License        */
  1290. X/*  along with this program; if not, write to the Free Software              */
  1291. X/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  1292. X/*                                                                           */
  1293. X/*  FILE:         z20.c                                                      */
  1294. X/*  MODULE:       Galley Flushing                                            */
  1295. X/*  EXTERNS:      FlushGalley()                                              */
  1296. X/*                                                                           */
  1297. X/*****************************************************************************/
  1298. X#include "externs"
  1299. X
  1300. X
  1301. X/*****************************************************************************/
  1302. X/*                                                                           */
  1303. X/*  ParentFlush(dest_index, kill)                                            */
  1304. X/*                                                                           */
  1305. X/*  Flush the galley which is the parent of dest_index, if likely to flush.  */
  1306. X/*  If kill is TRUE, delete dest_index.                                      */
  1307. X/*                                                                           */
  1308. X/*****************************************************************************/
  1309. X
  1310. X#define ParentFlush(dest_index, kill)                    \
  1311. Xif( prnt_flush )                            \
  1312. X{ debug0(DGF,D, "  ParentFlush calling FlushGalley (prnt)");        \
  1313. X  Parent(prnt, Up(dest_index));                        \
  1314. X  if( kill )  DeleteNode(dest_index);                    \
  1315. X  debug0(DGF, D, "  calling FlushGalley from ParentFlush");        \
  1316. X  FlushGalley(prnt);                            \
  1317. X  prnt_flush = FALSE;                            \
  1318. X}                                    \
  1319. Xelse if( kill )  DeleteNode(dest_index)
  1320. X
  1321. X
  1322. X/*@::FlushGalley()@***********************************************************/
  1323. X/*                                                                           */
  1324. X/*  FlushGalley(hd)                                                          */
  1325. X/*                                                                           */
  1326. X/*  Flush galley hd as far as possible.  It could be the root galley.        */
  1327. X/*                                                                           */
  1328. X/*****************************************************************************/
  1329. X
  1330. XFlushGalley(hd)
  1331. XOBJECT hd;
  1332. X{ OBJECT dest;            /* the target galley hd empties into         */
  1333. X  OBJECT dest_index;        /* the index of dest                         */
  1334. X  OBJECT inners;        /* list of galleys and PRECEDES to flush     */
  1335. X  OBJECT link, y;        /* for scanning through the components of hd */
  1336. X
  1337. X  CONSTRAINT dest_constraint;    /* the vertical size constraint on dest      */
  1338. X  int f;            /* candidate replacement value for dest_fwd  */
  1339. X
  1340. X  OBJECT dest_encl;        /* the VCAT enclosing dest, if any           */
  1341. X  int    dest_side;        /* if dest_encl != nil, the side dest is on  */
  1342. X  BOOLEAN need_adjust;        /* TRUE as soon as dest_encl needs adjusting */
  1343. X  LENGTH dest_back, dest_fwd;    /* the current size of dest_encl or dest     */
  1344. X  LENGTH frame_size;        /* the total constraint of dest_encl         */
  1345. X  OBJECT prec_gap;        /* the gap preceding dest, if any, else nil  */
  1346. X  OBJECT prec_def;        /* the component preceding dest, if any      */
  1347. X  OBJECT succ_gap;        /* the gap following dest, if any, else nil  */
  1348. X  OBJECT succ_def;        /* the component following dest, if any      */
  1349. X  OBJECT stop_link;        /* most recently seen gap link of hd         */
  1350. X  BOOLEAN prnt_flush;        /* TRUE when the parent of hd needs a flush  */
  1351. X  OBJECT zlink, z, tmp, prnt;
  1352. X
  1353. X  debug1(DGF, D, "[ FlushGalley %s (hd)", SymName(actual(hd)));
  1354. X  prnt_flush = FALSE;
  1355. X
  1356. X  RESUME:
  1357. X  assert( type(hd) == HEAD, "FlushGalley: type(hd) != HEAD!" );
  1358. X  debug1(DGF, D, "  resuming FlushGalley %s, hd =", SymName(actual(hd)));
  1359. X  ifdebug(DGF, DD, DebugObject(hd));
  1360. X  assert( Up(hd) != hd, "FlushGalley: resume found no parent to hd!" );
  1361. X
  1362. X
  1363. X  /*@@************************************************************************/
  1364. X  /*                                                                         */
  1365. X  /*  The first step is to examine the parent of galley hd to determine the  */
  1366. X  /*  status of the galley.  If this is not suitable for flushing, we do     */
  1367. X  /*  what we can to change the status.  If still no good, return; so if     */
  1368. X  /*  this code does not return, then the galley is ready to flush into a    */
  1369. X  /*  destination in the normal way, and the following variables are set:    */
  1370. X  /*                                                                         */
  1371. X  /*     dest_index   the parent of the galley and index of its destination  */
  1372. X  /*     dest         the destination of the galley, a @Galley object        */
  1373. X  /*                                                                         */
  1374. X  /***************************************************************************/
  1375. X
  1376. X  Parent(dest_index, Up(hd));
  1377. X  switch( type(dest_index) )
  1378. X  {
  1379. X
  1380. X    case DEAD:
  1381. X    
  1382. X      /* the galley has been killed off while this process was sleeping */
  1383. X      debug1(DGF, D, "] FlushGalley %s returning (DEAD)", SymName(actual(hd)));
  1384. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  1385. X      return;
  1386. X
  1387. X
  1388. X    case UNATTACHED:
  1389. X    
  1390. X      /* the galley is currently not attached to a destination */
  1391. X      AttachGalley(hd, &inners);
  1392. X      Parent(dest_index, Up(hd));
  1393. X      if( type(dest_index)!=RECEIVING || actual(actual(dest_index))==InputSym )
  1394. X      {    if( type(dest_index) != DEAD )
  1395. X    { ParentFlush(dest_index, FALSE);
  1396. X      if( inners != nil ) FlushInners(inners, nil);
  1397. X    }
  1398. X    debug1(DGF,D,"] FlushGalley %s retn, no attach", SymName(actual(hd)));
  1399. X    debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  1400. X    return;
  1401. X      }
  1402. X
  1403. X      /* if hd is a forcing galley, close all predecessors */
  1404. X      if( actual(hd) != nil && force_target(actual(hd)) )
  1405. X      {    Parent(prnt, Up(dest_index));
  1406. X    debug0(DGA, DD, "  force: prnt =");
  1407. X    ifdebug(DGA, DD, DebugObject(prnt));
  1408. X    debug1(DGA, D,"  calling FreeGalley from FlushGalley(%s)",
  1409. X      SymName(actual(hd)));
  1410. X    FreeGalley(prnt, Up(dest_index), &inners, Up(dest_index), whereto(hd));
  1411. X    prnt_flush = TRUE;
  1412. X    debug0(DGA, DD, "  force: after FreeGalley, prnt =");
  1413. X    ifdebug(DGA, DD, DebugObject(prnt));
  1414. X      }
  1415. X      else prnt_flush = prnt_flush || blocked(dest_index);
  1416. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  1417. X
  1418. X      if( inners != nil ) FlushInners(inners, nil);
  1419. X      goto RESUME;
  1420. X      break;
  1421. X
  1422. X
  1423. X    case RECEIVING:
  1424. X    
  1425. X      if( actual(actual(dest_index)) == InputSym )
  1426. X      { ParentFlush(dest_index, FALSE);
  1427. X    debug1(DGF, D, "] FlushGalley %s retn, input", SymName(actual(hd)));
  1428. X    debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  1429. X    return;
  1430. X      }
  1431. X      break;
  1432. X
  1433. X
  1434. X    default:
  1435. X    
  1436. X      Error(INTERN, &fpos(hd), "FlushGalley: %s ind!", Image(type(dest_index)));
  1437. X      break;
  1438. X  }
  1439. X  dest = actual(dest_index);
  1440. X  debug1(DGF, DD, "  dest_index: %s", EchoObject(dest_index));
  1441. X
  1442. X
  1443. X  /*@@************************************************************************/
  1444. X  /*                                                                         */
  1445. X  /*  The second step is to examine the components of the galley one by one  */
  1446. X  /*  to determine if they can be promoted.  Each component has the format   */
  1447. X  /*                                                                         */
  1448. X  /*    { <index> } <object>                                                 */
  1449. X  /*                                                                         */
  1450. X  /*  and is always followed by a gap object (except the last component).    */
  1451. X  /*  An index indicates that the following object has some interesting      */
  1452. X  /*  feature, and it points to that feature inside the object.  There are   */
  1453. X  /*  two possible actions for each component, in addition to accepting it:  */
  1454. X  /*                                                                         */
  1455. X  /*    REJECT:   The component does not fit, so detach the galley           */
  1456. X  /*    SUSPEND:  The component is incomplete; go to sleep and wait          */
  1457. X  /*                                                                         */
  1458. X  /***************************************************************************/
  1459. X
  1460. X  stop_link = dest_encl = inners = nil;
  1461. X  need_adjust = FALSE;
  1462. X
  1463. X  /***************************************************************************/
  1464. X  /*                                                                         */
  1465. X  /*  Loop invariant                                                         */
  1466. X  /*                                                                         */
  1467. X  /*  The children of hd up to but not including Child(link) have been       */
  1468. X  /*  examined and pronounced to be promotable.                              */
  1469. X  /*                                                                         */
  1470. X  /*  stop_link is the link of the most recently encountered gap object of   */
  1471. X  /*  hd, or nil if no gap object has been encountered yet.                  */
  1472. X  /*                                                                         */
  1473. X  /*  if dest_encl is non-nil, then the destination is not external,         */
  1474. X  /*  dest_encl is its parent, and the following variables are defined:      */
  1475. X  /*                                                                         */
  1476. X  /*    prec_gap         gap object preceding dest (which must exist)        */
  1477. X  /*    prec_def         first definite object preceding dest (must exist)   */
  1478. X  /*    dest_back        back(dest_encl) including effect of accepted compts */
  1479. X  /*    dest_fwd         fwd(dest_encl) including effect of accepted compts  */
  1480. X  /*    dest_side        BACK or FWD, i.e. which side of the mark dest is on */
  1481. X  /*    dest_constraint  the size constraint on dest                         */
  1482. X  /*    frame_size       size of frame enclosing dest_encl                   */
  1483. X  /*                                                                         */
  1484. X  /*  if dest_encl is nil, these variables are not defined.                  */
  1485. X  /*                                                                         */
  1486. X  /*  need_adjust is true if at least one definite component has been        */
  1487. X  /*  accepted for promotion and the destination is internal; hence,         */
  1488. X  /*  dest_encl is defined and its size needs to be adjusted.                */
  1489. X  /*                                                                         */
  1490. X  /*  inners is the set of all PRECEDES and UNATTACHED indexes found.        */
  1491. X  /*                                                                         */
  1492. X  /***************************************************************************/
  1493. X
  1494. X  for( link = Down(hd);  link != hd;  link = NextDown(link) )
  1495. X  {
  1496. X    Child(y, link);
  1497. X    if( type(y) == SPLIT )  Child(y, DownDim(y, ROW));
  1498. X    debug1(DGF, DD, "  try to flush %s", EchoObject(y));
  1499. X    switch( type(y) )
  1500. X    {
  1501. X
  1502. X      case GAP_OBJ:
  1503. X
  1504. X    prec_gap = y;
  1505. X    stop_link = link;
  1506. X    if( !join(gap(y)) )  seen_nojoin(hd) = TRUE;
  1507. X    break;
  1508. X
  1509. X
  1510. X      case EXPAND_IND:
  1511. X      case GALL_PREC:
  1512. X      case GALL_FOLL:
  1513. X      case GALL_TARG:
  1514. X      case CROSS_PREC:
  1515. X      case CROSS_FOLL:
  1516. X      case CROSS_TARG:
  1517. X
  1518. X    break;
  1519. X
  1520. X
  1521. X      case PRECEDES:
  1522. X      case UNATTACHED:
  1523. X      
  1524. X    if( inners == nil )  inners = New(ACAT);
  1525. X    Link(inners, y);
  1526. X    break;
  1527. X
  1528. X
  1529. X      case RECEIVING:
  1530. X      case RECEPTIVE:
  1531. X      
  1532. X    goto SUSPEND;
  1533. X
  1534. X
  1535. X      case FOLLOWS:
  1536. X      
  1537. X    Child(tmp, Down(y));
  1538. X    if( Up(tmp) == LastUp(tmp) )
  1539. X    { link = PrevDown(link);
  1540. X      DisposeChild(NextDown(link));
  1541. X      break;
  1542. X    }
  1543. X    Parent(tmp, Up(tmp));
  1544. X    assert(type(tmp) == PRECEDES, "Flush: PRECEDES!");
  1545. X    switch( CheckConstraint(tmp, dest_index) )
  1546. X    {
  1547. X      case CLEAR:    DeleteNode(tmp);
  1548. X            link = PrevDown(link);
  1549. X            DisposeChild(NextDown(link));
  1550. X            break;
  1551. X
  1552. X      case PROMOTE:    break;
  1553. X
  1554. X      case BLOCK:    goto SUSPEND;
  1555. X
  1556. X      case CLOSE:    goto REJECT;
  1557. X    }
  1558. X    break;
  1559. X
  1560. X
  1561. X      case WORD:
  1562. X      case QWORD:
  1563. X      case ONE_COL:
  1564. X      case ONE_ROW:
  1565. X      case WIDE:
  1566. X      case HIGH:
  1567. X      case HSCALE:
  1568. X      case VSCALE:
  1569. X      case HCONTRACT:
  1570. X      case VCONTRACT:
  1571. X      case HEXPAND:
  1572. X      case VEXPAND:
  1573. X      case PADJUST:
  1574. X      case HADJUST:
  1575. X      case VADJUST:
  1576. X      case ROTATE:
  1577. X      case SCALE:
  1578. X      case INCGRAPHIC:
  1579. X      case SINCGRAPHIC:
  1580. X      case GRAPHIC:
  1581. X      case ACAT:
  1582. X      case HCAT:
  1583. X      case ROW_THR:
  1584. X      case CLOSURE:
  1585. X      case NULL_CLOS:
  1586. X      case CROSS:
  1587. X
  1588. X    /* make sure y is not joined to a target below */
  1589. X    for( zlink = NextDown(link); zlink != hd; zlink = NextDown(zlink) )
  1590. X    { Child(z, zlink);
  1591. X      switch( type(z) )
  1592. X      {
  1593. X        case RECEPTIVE:
  1594. X        case RECEIVING:    y = z;
  1595. X                goto SUSPEND;
  1596. X                break;
  1597. X
  1598. X        case GAP_OBJ:    if( !join(gap(z)) )  zlink = PrevDown(hd);
  1599. X                break;
  1600. X
  1601. X        default:        break;
  1602. X      }
  1603. X    }
  1604. X
  1605. X    /* check size constraint */
  1606. X    if( !external(dest) )
  1607. X    {
  1608. X      /* initialise dest_encl etc if not done yet */
  1609. X      if( dest_encl == nil )
  1610. X      { assert( UpDim(dest,COL) == UpDim(dest,ROW), "FlushG: UpDims!" );
  1611. X        Parent(dest_encl, NextDown(Up(dest)));
  1612. X        assert( type(dest_encl) == VCAT, "FlushGalley: dest != VCAT!" );
  1613. X        SetNeighbours(Up(dest), FALSE, &prec_gap, &prec_def,
  1614. X          &succ_gap, &succ_def, &dest_side);
  1615. X        assert(prec_gap != nil || is_indefinite(type(y)),
  1616. X          "FlushGalley: prec_gap == nil && !is_indefinite(type(y))!" );
  1617. X        assert(succ_gap == nil, "FlushGalley: succ_gap != nil!" );
  1618. X        assert(dest_side == FWD || is_indefinite(type(y)),
  1619. X          "FlushGalley: dest_side != FWD || !is_indefinite(type(y))!");
  1620. X        dest_back = back(dest_encl, ROW);
  1621. X        dest_fwd  = fwd(dest_encl, ROW);
  1622. X        Constrained(dest_encl, &dest_constraint, ROW);
  1623. X        frame_size = constrained(dest_constraint) ? bfc(dest_constraint) :0;
  1624. X      }
  1625. X
  1626. X      if( !is_indefinite(type(y)) )
  1627. X      { /* calculate effect of adding y to dest */
  1628. X        f = dest_fwd  + fwd(y, ROW) - fwd(prec_def, ROW) +
  1629. X          ActualGap(fwd(prec_def, ROW), back(y, ROW),
  1630. X            fwd(y, ROW), &gap(prec_gap), frame_size,
  1631. X            dest_back + dest_fwd - fwd(prec_def, ROW));
  1632. X        debug3(DGF, DD, "  b,f: %s,%s;   dest_encl: %s",
  1633. X            EchoLength(dest_back), EchoLength(f),
  1634. X            EchoConstraint(&dest_constraint));
  1635. X
  1636. X        /* check new size against constraint */
  1637. X        if( !FitsConstraint(dest_back,f,dest_constraint) )
  1638. X          goto REJECT;
  1639. X        if( units(gap(prec_gap))==FRAME_UNIT && width(gap(prec_gap)) > FR )
  1640. X          goto REJECT;
  1641. X
  1642. X        /* accept component */
  1643. X        dest_fwd = f;  prec_def = y;
  1644. X        need_adjust = TRUE;
  1645. X      }
  1646. X
  1647. X    } /* end if( !external(dest) ) */
  1648. X
  1649. X    /* accept this component into dest */
  1650. X    debug1(DGF, D, "  accept %s", EchoObject(y));
  1651. X    prnt_flush = prnt_flush || blocked(dest_index);
  1652. X    debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  1653. X    if( inners != nil )
  1654. X    { Promote(hd, NextDown(link), dest_index);
  1655. X      if( need_adjust )
  1656. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (ACCEPT)");
  1657. X        AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  1658. X      }
  1659. X      FlushInners(inners, hd);
  1660. X      goto RESUME;
  1661. X    }
  1662. X    break;
  1663. X
  1664. X
  1665. X      default:
  1666. X      
  1667. X    Error(INTERN, &fpos(y), "FlushGalley: %s", Image(type(y)));
  1668. X    break;
  1669. X
  1670. X    } /* end switch */
  1671. X
  1672. X  } /* end for */
  1673. X
  1674. X
  1675. X  /* EMPTY: */
  1676. X
  1677. X    /* galley is now completely accepted; clean up and exit */
  1678. X    debug0(DGF, DD, "  galley empty now");
  1679. X    if( inners != nil )  DisposeObject(inners);
  1680. X    if( Down(hd) != hd )
  1681. X    { Promote(hd, hd, dest_index);
  1682. X      if( need_adjust )
  1683. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (EMPTY)");
  1684. X    AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  1685. X      }
  1686. X    }
  1687. X    DetachGalley(hd);
  1688. X    debug0(DGF, D, "  calling KillGalley from FlushGalley");
  1689. X    KillGalley(hd);
  1690. X    ParentFlush(dest_index, TRUE);
  1691. X    debug1(DGF,D,"] FlushGalley %s returning (emptied).", SymName(actual(hd)));
  1692. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  1693. X    return;
  1694. X
  1695. X
  1696. X  REJECT:
  1697. X  
  1698. X    /* reject this component and move to a new dest */
  1699. X    debug1(DGF, D, "  reject %s", EchoObject(y));
  1700. X    assert(actual(dest) != PrintSym, "FlushGalley: reject print!");
  1701. X    if( inners != nil )  DisposeObject(inners);
  1702. X    if( stop_link != nil )
  1703. X    { Promote(hd, stop_link, dest_index);
  1704. X      if( need_adjust )
  1705. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (REJECT)");
  1706. X    AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  1707. X      }
  1708. X    }
  1709. X    DetachGalley(hd);
  1710. X    assert( type(dest_index) == RECEIVING, "FlushGalley/REJECT: dest_index!" );
  1711. X    prnt_flush = prnt_flush || blocked(dest_index); /* **** bug fix **** */
  1712. X    DeleteNode(dest_index);
  1713. X    goto RESUME;
  1714. X
  1715. X
  1716. X  SUSPEND:
  1717. X  
  1718. X    /* suspend this component */
  1719. X    debug1(DGF, D, "  suspend %s", EchoObject(y));
  1720. X    if( inners != nil )  DisposeObject(inners);
  1721. X    if( stop_link != nil )
  1722. X    { Promote(hd, stop_link, dest_index);
  1723. X      if( need_adjust )
  1724. X      { debug0(DSA, D, "  calling AdjustSize from FlushGalley (SUSPEND)");
  1725. X    AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  1726. X      }
  1727. X    }
  1728. X
  1729. X    /* check whether external galleys can remove the blockage */
  1730. X    if( type(y) == RECEPTIVE && ready_galls(hd) != nil && AllowCrossDb )
  1731. X    { OBJECT eg, val, index2, hd2, tag, seq, newsym;
  1732. X      BOOLEAN found, gall;  FULL_CHAR newtag[MAX_LINE], newseq[MAX_LINE];
  1733. X
  1734. X      /* get first ready galley in from cross reference database */
  1735. X      Child(eg, Down(ready_galls(hd)));
  1736. X      val = ReadFromFile(eg_fnum(eg), eg_fpos(eg), nil);
  1737. X      if( val == nil ) Error(FATAL, &fpos(y),
  1738. X    "Error in database file %s", FileName(eg_fnum(eg)));
  1739. X      assert( type(val) == CLOSURE, "AttachG: db CLOSURE!" );
  1740. X      index2 = New(UNATTACHED);
  1741. X      hd2 = New(HEAD);
  1742. X      FposCopy(fpos(hd2), fpos(val));
  1743. X      actual(hd2) = actual(val);
  1744. X      backward(hd2) = TargetSymbol(val, &whereto(hd2));
  1745. X      backward(hd2) = sized(hd2) = FALSE;
  1746. X      ready_galls(hd2) = nil;
  1747. X      must_expand(hd2) = TRUE;
  1748. X      Link(index2, hd2);
  1749. X      Link(hd2, val);
  1750. X      Link(Up(y), index2);
  1751. X
  1752. X      /* set up the next ready galley for reading next time */
  1753. X      Child(tag, Down(eg));  Child(seq, LastDown(eg));
  1754. X      do /* skip duplicate seq values */
  1755. X      {    found = DbRetrieveNext(OldCrossDb, &gall, &newsym,
  1756. X         newtag, newseq, &eg_fnum(eg), &eg_fpos(eg), &eg_cont(eg));
  1757. X    debug2(DGF, D, "  ext gall  found:   %15s  gall:    %15s",
  1758. X            bool(gall), bool(found));
  1759. X    debug2(DGF, D, "  ext gall  new sym: %15s  old sym: %15s",
  1760. X            SymName(newsym), SymName(eg_symbol(eg)));
  1761. X    debug2(DGF, D, "  ext gall  new tag: %15s  old tag: %15s",
  1762. X            newtag, string(tag));
  1763. X    debug2(DGF, D, "  ext gall  new seq: %15s  old seq: %15s",
  1764. X            newseq, string(seq));
  1765. X    if( found )  found = gall && newsym == eg_symbol(eg) &&
  1766. X            StringEqual(newtag, string(tag));
  1767. X      } while( found && StringEqual(newseq, string(seq)) );
  1768. X      if( found )
  1769. X      {    DisposeChild(Up(tag));
  1770. X    DisposeChild(Up(seq));
  1771. X    tag = MakeWord(WORD, newtag, no_fpos);
  1772. X    seq = MakeWord(WORD, newseq, no_fpos);
  1773. X    Link(eg, tag);  Link(eg, seq);
  1774. X    debug1(DGF,D, "  another ext gall: into %s", SymName(newsym));
  1775. X      }
  1776. X      else
  1777. X      {    DisposeChild(Up(eg));
  1778. X    debug1(DGF,D, "  last ext gall into ", SymName(eg_symbol(eg)));
  1779. X    if( Down(ready_galls(hd)) == ready_galls(hd) )
  1780. X    { Dispose(ready_galls(hd));
  1781. X      ready_galls(hd) = nil;
  1782. X      debug0(DGF,D, "  all ext galls exhausted");
  1783. X    }
  1784. X      }
  1785. X
  1786. X      /* flush the ready galley found above, and resume */
  1787. X      debug2(DGF, D, "  ext gall FlushGalley (%s into %s)",
  1788. X            SymName(actual(hd2)), SymName(whereto(hd2)));
  1789. X      debug0(DGF, D, "  calling FlushGalley from FlushGalley/SUSPEND");
  1790. X      FlushGalley(hd2);
  1791. X      goto RESUME;
  1792. X    }
  1793. X    else if( type(y) == RECEPTIVE && trigger_externs(y) && AllowCrossDb )
  1794. X    { OBJECT sym, cr, ins, tag, seq, eg, cnt;  BOOLEAN found;
  1795. X      FULL_CHAR newseq[MAX_LINE];  FILE_NUM tfnum;  long tfpos, tcont;
  1796. X      debug1(DGF, D, "  ext gall target %s", SymName(actual(actual(y))));
  1797. X      for( sym = FirstExternTarget(actual(actual(y)), &cnt);
  1798. X         sym != nil;  sym = NextExternTarget(actual(actual(y)), &cnt) )
  1799. X      {
  1800. X    debug1(DGF, D, "  ext gall gall_targ %s", SymName(sym));
  1801. X    cr = GallTargEval(sym, &fpos(actual(y)));
  1802. X    ins = New(GALL_TARG);
  1803. X    actual(ins) = cr;
  1804. X    Link(Up(y), ins);
  1805. X    Child(tag, LastDown(cr));
  1806. X    assert( is_word(type(tag)), "FlushGalley: cr is_word(type(tag))!" );
  1807. X    found = DbRetrieve(OldCrossDb, TRUE, sym, string(tag),
  1808. X        newseq, &tfnum, &tfpos, &tcont);
  1809. X    if( found )
  1810. X    { if( ready_galls(hd) == nil )  ready_galls(hd) = New(ACAT);
  1811. X      eg = New(EXT_GALL);
  1812. X      debug1(DGF, D, "  ext gall retrieved: into %s", SymName(sym));
  1813. X      eg_fnum(eg) = tfnum;
  1814. X      eg_fpos(eg) = tfpos;
  1815. X      eg_symbol(eg) = sym;
  1816. X      eg_cont(eg) = tcont;
  1817. X      tag = MakeWord(WORD, string(tag), no_fpos);
  1818. X      Link(eg, tag);
  1819. X      seq = MakeWord(WORD, newseq, no_fpos);
  1820. X      Link(eg, seq);
  1821. X      Link(ready_galls(hd), eg);
  1822. X    }
  1823. X      }
  1824. X      trigger_externs(y) = FALSE;
  1825. X      if( ready_galls(hd) != nil )  goto RESUME;
  1826. X    } /* end if external galleys */
  1827. X
  1828. X    /* if non-blocking, delete the index and resume */
  1829. X    if( type(y) == RECEPTIVE && non_blocking(y) )
  1830. X    { DeleteNode(y);
  1831. X      goto RESUME;
  1832. X    }
  1833. X    else if( type(y) == RECEIVING && non_blocking(y) )
  1834. X    {    
  1835. X      if( Down(y) == y )
  1836. X      {    DeleteNode(y);
  1837. X      }
  1838. X      else
  1839. X      {    Child(z, Down(y));
  1840. X    DetachGalley(z);
  1841. X      }
  1842. X      goto RESUME;
  1843. X    }
  1844. X
  1845. X    /* if all the above fail to remove the blockage, suspend */
  1846. X    blocked(y) = TRUE;
  1847. X    ParentFlush(dest_index, FALSE);
  1848. X      debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  1849. X    debug1(DGF, D, "] FlushGalley %s returning (suspend)", SymName(actual(hd)));
  1850. X    return;
  1851. X
  1852. X} /* end FlushGalley */
  1853. END_OF_FILE
  1854.   if test 22867 -ne `wc -c <'z20.c'`; then
  1855.     echo shar: \"'z20.c'\" unpacked with wrong size!
  1856.   fi
  1857.   # end of 'z20.c'
  1858. fi
  1859. echo shar: End of archive 13 \(of 35\).
  1860. cp /dev/null ark13isdone
  1861. MISSING=""
  1862. 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 31 32 33 34 35 ; do
  1863.     if test ! -f ark${I}isdone ; then
  1864.     MISSING="${MISSING} ${I}"
  1865.     fi
  1866. done
  1867. if test "${MISSING}" = "" ; then
  1868.     echo You have unpacked all 35 archives.
  1869.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1870. else
  1871.     echo You still must unpack the following archives:
  1872.     echo "        " ${MISSING}
  1873. fi
  1874. exit 0
  1875. exit 0 # Just in case...
  1876.