diff options
author | Jeffrey H. Kingston <jeff@it.usyd.edu.au> | 2010-09-14 19:21:41 +0000 |
---|---|---|
committer | Jeffrey H. Kingston <jeff@it.usyd.edu.au> | 2010-09-14 19:21:41 +0000 |
commit | 71bdb35d52747e6d7d9f55df4524d57c2966be94 (patch) | |
tree | 480ee5eefccc40d5f3331cc52d66f722fd19bfb9 /z08.c | |
parent | b41263ea7578fa9742486135c762803b52794105 (diff) | |
download | lout-71bdb35d52747e6d7d9f55df4524d57c2966be94.tar.gz |
Lout 3.17.
git-svn-id: http://svn.savannah.nongnu.org/svn/lout/trunk@2 9365b830-b601-4143-9ba8-b4a8e2c3339c
Diffstat (limited to 'z08.c')
-rw-r--r-- | z08.c | 1989 |
1 files changed, 1989 insertions, 0 deletions
@@ -0,0 +1,1989 @@ +/*@z08.c:Object Manifest:ReplaceWithSplit()@**********************************/ +/* */ +/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.17) */ +/* COPYRIGHT (C) 1991, 1999 Jeffrey H. Kingston */ +/* */ +/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */ +/* Basser Department of Computer Science */ +/* The University of Sydney 2006 */ +/* AUSTRALIA */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either Version 2, or (at your option) */ +/* any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */ +/* */ +/* FILE: z08.c */ +/* MODULE: Object Manifest */ +/* EXTERNS: Manifest() */ +/* */ +/*****************************************************************************/ +#include "externs.h" +#define line_breaker(g) \ + (vspace(g) > 0 || (units(gap(g)) == FRAME_UNIT && width(gap(g)) > FR)) + + +/*****************************************************************************/ +/* */ +/* static SetUnderline(x) */ +/* */ +/* Set underline() flags in object x to UNDER_ON as appropriate. */ +/* */ +/*****************************************************************************/ + +static void SetUnderline(OBJECT x) +{ OBJECT y, link; + debug2(DOM, DD, " Manifest underlining %s %s", Image(type(x)),EchoObject(x)); + if( type(x) == ACAT ) + { for( link = Down(x); link != x; link = NextDown(link) ) + { Child(y, link); + SetUnderline(y); + } + } + debug3(DOM, DDD, " SetUnderline underline() := %s for %s %s", + "UNDER_ON", Image(type(x)), EchoObject(x)); + underline(x) = UNDER_ON; +} /* end SetUnderline */ + + +/*****************************************************************************/ +/* */ +/* static ReplaceWithSplit(x, bthr, fthr) */ +/* */ +/* Replace object x with a SPLIT object, if threads for this object are */ +/* requested by bthr and/or fthr. */ +/* */ +/*****************************************************************************/ + +#define ReplaceWithSplit(x, bthr, fthr) \ + if( bthr[ROWM] || bthr[COLM] || fthr[ROWM] || fthr[COLM] ) \ + x = insert_split(x, bthr, fthr) + +static OBJECT insert_split(OBJECT x, OBJECT bthr[2], OBJECT fthr[2]) +{ OBJECT res, new_op; int dim; + debug1(DOM, DD, "ReplaceWithSplit(%s, -)", EchoObject(x)); + assert( type(x) != SPLIT, "ReplaceWithSplit: type(x) already SPLIT!" ); + New(res, SPLIT); + FposCopy(fpos(res), fpos(x)); + ReplaceNode(res, x); + for( dim = COLM; dim <= ROWM; dim++ ) + { if( bthr[dim] || fthr[dim] ) + { New(new_op, dim == COLM ? COL_THR : ROW_THR); + thr_state(new_op) = NOTSIZED; + fwd(new_op, 1-dim) = 0; /* will hold max frame_size */ + back(new_op, 1-dim) = 0; /* will hold max frame_origin */ + FposCopy(fpos(new_op), fpos(x)); + Link(res, new_op); Link(new_op, x); + if( bthr[dim] ) Link(bthr[dim], new_op); + if( fthr[dim] ) Link(fthr[dim], new_op); + } + else Link(res, x); + } + + debug1(DOM, DD, "ReplaceWithSplit returning %s", EchoObject(res)); + return res; +} /* end insert_split */ + +/*@::ReplaceWithTidy()@*******************************************************/ +/* */ +/* OBJECT ReplaceWithTidy(x, one_word) */ +/* */ +/* Replace object x with a tidier version in which juxtapositions are */ +/* folded. If this is not possible, return the original object. */ +/* */ +/* If one_word is TRUE, the result is to be a single QWORD with inter- */ +/* word spaces converted to single space characters. Otherwise an ACAT */ +/* is the preferred result. */ +/* */ +/* *** Meaning changed, now interword spaces are converted to the same */ +/* number of spaces to assist construction of sorting keys. */ +/* */ +/*****************************************************************************/ + +OBJECT ReplaceWithTidy(OBJECT x, BOOLEAN one_word) +{ static FULL_CHAR buff[MAX_BUFF]; /* the growing current word */ + static int buff_len; /* length of current word */ + static FILE_POS buff_pos; /* filepos of current word */ + static unsigned buff_typ; /* WORD or QWORD of current */ + OBJECT link, y, tmp, res; /* temporaries */ + int i; + debug2(DOM, DD, "ReplaceWithTidy(%s, %s)", EchoObject(x), bool(one_word)); + switch( type(x) ) + { + case ACAT: + + for( link = Down(x); link != x; link = NextDown(link) ) + { Child(y, link); + if( type(y) == ACAT ) + { tmp = Down(y); TransferLinks(tmp, y, link); + DisposeChild(link); link = PrevDown(tmp); + } + } + res = nilobj; buff_len = 0; buff_typ = WORD; + FposCopy(buff_pos, fpos(x)); + for( link = Down(x); link != x; link = NextDown(link) ) + { Child(y, link); + if( is_word(type(y)) ) + { if( buff_len + StringLength(string(y)) >= MAX_BUFF ) + Error(8, 1, "word is too long", WARN, &fpos(y)); + else + { if( buff_len == 0 ) FposCopy(buff_pos, fpos(y)); + StringCopy(&buff[buff_len], string(y)); + buff_len += StringLength(string(y)); + if( type(y) == QWORD ) buff_typ = QWORD; + } + } + else if( type(y) == GAP_OBJ ) + { if( Down(y) != y || hspace(y) + vspace(y) > 0 ) + { if( one_word ) + { if( buff_len + hspace(y) + vspace(y) >= MAX_BUFF ) + Error(8, 2, "word is too long", WARN, &fpos(y)); + else + { for( i = 0; i < hspace(y) + vspace(y); i++ ) + { StringCopy(&buff[buff_len], AsciiToFull(" ")); + buff_len++; + } + buff_typ = QWORD; + } + } + else + { tmp = MakeWord(buff_typ, buff, &buff_pos); + buff_len = 0; buff_typ = WORD; + if( res == nilobj ) + { New(res, ACAT); + FposCopy(fpos(res), fpos(x)); + } + Link(res, tmp); Link(res, y); + } + } + } + else /* error */ + { if( res != nilobj ) DisposeObject(res); + debug0(DOM, DD, "ReplaceWithTidy returning unchanged"); + return x; + } + } + tmp = MakeWord(buff_typ, buff, &buff_pos); + if( res == nilobj ) res = tmp; + else Link(res, tmp); + ReplaceNode(res, x); DisposeObject(x); + debug1(DOM, DD, "ReplaceWithTidy returning %s", EchoObject(res)); + return res; + + + case WORD: + case QWORD: + + debug1(DOM, DD, "ReplaceWithTidy returning %s", EchoObject(x)); + return x; + + + default: + + debug0(DOM, DD, "ReplaceWithTidy returning unchanged"); + return x; + } +} /* end ReplaceWithTidy */ + + +/*@::GetScaleFactor()@********************************************************/ +/* */ +/* static float GetScaleFactor(x) */ +/* */ +/* Find a scale factor in object x and return it as a float, after checks. */ +/* */ +/*****************************************************************************/ + +static float GetScaleFactor(OBJECT x) +{ float scale_factor; + if( !is_word(type(x)) ) + { Error(8, 3, "replacing invalid scale factor by 1.0", WARN, &fpos(x)); + scale_factor = 1.0; + } + else if( sscanf( (char *) string(x), "%f", &scale_factor) != 1 ) + { Error(8, 4, "replacing invalid scale factor %s by 1.0", + WARN, &fpos(x), string(x)); + scale_factor = 1.0; + } + else if( scale_factor < 0.01 ) + { Error(8, 5, "replacing undersized scale factor %s by 1.0", + WARN, &fpos(x), string(x)); + scale_factor = 1.0; + } + else if( scale_factor > 100 ) + { Error(8, 6, "replacing oversized scale factor %s by 1.0", + WARN, &fpos(x), string(x)); + scale_factor = 1.0; + } + return scale_factor; +} /* GetScaleFactor */ + + +static OBJECT nbt[2] = { nilobj, nilobj }; /* constant nilobj threads */ +static OBJECT nft[2] = { nilobj, nilobj }; /* constant nilobj threads */ +static OBJECT ntarget = nilobj; /* constant nilobj target */ +static OBJECT nenclose = nilobj; /* constant nilobj enclose */ + + +/*@::ManifestCat@*************************************************************/ +/* */ +/* OBJECT ManifestCat(x,env,style,bthr, fthr, target, crs, ok, need_expand, */ +/* enclose, fcr) */ +/* */ +/* This procedure implements Manifest (see below) when x is HCAT or VCAT. */ +/* */ +/*****************************************************************************/ + +static OBJECT ManifestCat(OBJECT x, OBJECT env, STYLE *style, OBJECT bthr[2], +OBJECT fthr[2], OBJECT *target, OBJECT *crs, BOOLEAN ok, BOOLEAN need_expand, +OBJECT *enclose, BOOLEAN fcr) +{ OBJECT bt[2], ft[2], y, link, gaplink, g, first_bt, last_ft, z; + int par, perp; + unsigned res_inc; BOOLEAN still_backing; + STYLE new_style; + debug1(DOM, DD, "[ ManifestCat(%s)", EchoObject(x)); + + StyleCopy(new_style, *style); + if( type(x) == HCAT ) + { par = ROWM; + adjust_cat(x) = hadjust(*style); + hadjust(new_style) = FALSE; + } + else + { par = COLM; + adjust_cat(x) = vadjust(*style); + vadjust(new_style) = FALSE; + } + perp = 1 - par; + link = Down(x); + gaplink = NextDown(link); + assert( link!=x && gaplink!=x, "Manifest/VCAT: less than two children!" ); + Child(y, link); Child(g, gaplink); + + /* set bt and ft threads for y */ + bt[perp] = bthr[perp]; + ft[perp] = fthr[perp]; + if( bthr[par] ) { New(first_bt, THREAD); } + else first_bt = nilobj; + bt[par] = first_bt; + if( join(gap(g)) ) { New(ft[par], THREAD); } + else ft[par] = nilobj; + still_backing = first_bt != nilobj; + + /* manifest y and insinuate any cross-references */ + y = Manifest(y, env, &new_style, bt, ft, target, crs, ok, FALSE, enclose, fcr); + if( type(x) == VCAT && ok && *crs != nilobj ) + { debug1(DCR, DD, " insinuating %s", EchoObject(*crs)); + TransferLinks(Down(*crs), *crs, link); + DisposeObject(*crs); + *crs = nilobj; + } + + /* manifest the remaining children */ + while( g != nilobj ) + { + /* manifest the gap object, store it in gap(g), add perp threads */ + assert( type(g) == GAP_OBJ, "Manifest/VCAT: type(g) != GAP_OBJECT!" ); + assert( Down(g) != g, "Manifest/VCAT: GAP_OBJ has no child!" ); + Child(z, Down(g)); + debug1(DOM, DD, "manifesting gap, style = %s", EchoStyle(style)); + z = Manifest(z, env, &new_style, nbt, nft, &ntarget, crs, FALSE, FALSE, enclose, fcr); + debug1(DOM, DD, "replacing with tidy, style = %s", EchoStyle(style)); + z = ReplaceWithTidy(z, FALSE); + debug1(DOM, DD, "calling GetGap, style = %s", EchoStyle(style)); + GetGap(z, style, &gap(g), &res_inc); + if( bt[perp] ) Link(bt[perp], g); + if( ft[perp] ) Link(ft[perp], g); + + /* find the next child y, and following gap if any */ + link = NextDown(gaplink); + assert( link != x, "Manifest/VCAT: GAP_OBJ is last child!" ); + Child(y, link); + gaplink = NextDown(link); + if( gaplink == x ) g = nilobj; + else Child(g, gaplink); + + /* set bt and ft threads for y */ + last_ft = ft[par]; + if( ft[par] ) { New(bt[par], THREAD); } else bt[par] = nilobj; + if( g != nilobj ) + { if( join(gap(g)) ) { New(ft[par], THREAD); } else ft[par] = nilobj; + } + else + { + if( fthr[par] ) { New(ft[par], THREAD); } else ft[par] = nilobj; + } + + /* manifest y and insinuate any cross references */ + y = Manifest(y, env, &new_style, bt, ft, target, crs, ok, FALSE, enclose, fcr); + if( type(x) == VCAT && ok && *crs != nilobj ) + { debug1(DCR, DD, " insinuating %s", EchoObject(*crs)); + TransferLinks(Down(*crs), *crs, link); + DisposeObject(*crs); + *crs = nilobj; + } + + if( bt[par] ) /* then thread lists last_ft and bt[par] must merge */ + { OBJECT llink, rlink, lthread, rthread; + BOOLEAN goes_through; + assert( Down(bt[par]) != bt[par], "Manifest: bt[par] no children!" ); + assert( last_ft!=nilobj && Down(last_ft)!=last_ft, "Manifest:last_ft!" ); + + /* check whether marks run right through y in par direction */ + goes_through = FALSE; + if( ft[par] ) + { assert( Down(ft[par]) != ft[par], "Manifest: ft[par] child!" ); + Child(lthread, LastDown(bt[par])); + Child(rthread, LastDown(ft[par])); + goes_through = lthread == rthread; + } + + /* merge the thread lists */ + llink = Down(last_ft); rlink = Down(bt[par]); + while( llink != last_ft && rlink != bt[par] ) + { Child(lthread, llink); + Child(rthread, rlink); + assert( lthread != rthread, "Manifest: lthread == rthread!" ); + MergeNode(lthread, rthread); + llink = NextDown(llink); + rlink = NextDown(rlink); + } + + /* attach leftover back threads to first_bt if required */ + if( rlink != bt[par] ) + { + if( still_backing ) TransferLinks(rlink, bt[par], first_bt); + } + DisposeObject(bt[par]); + + /* attach leftover forward threads to ft[par] if required */ + if( llink != last_ft ) + { + if( goes_through ) TransferLinks(llink, last_ft, ft[par]); + } + DisposeObject(last_ft); + + if( !goes_through ) still_backing = FALSE; + + } + else still_backing = FALSE; + + } /* end while */ + + /* export par threads */ + if( fthr[par] ) MergeNode(fthr[par], ft[par]); + if( bthr[par] ) MergeNode(bthr[par], first_bt); + debug0(DOM, DD, "] ManifestCat returning"); + return x; +} /* end ManifestCat */ + + +/*@::ManifestCase@************************************************************/ +/* */ +/* OBJECT ManifestCase(x,env,style,bthr,fthr, target, crs, ok, need_expand, */ +/* enclose, fcr) */ +/* */ +/* This procedure implements Manifest (see below) when x is CASE. */ +/* */ +/*****************************************************************************/ + +static OBJECT ManifestCase(OBJECT x, OBJECT env, STYLE *style, OBJECT bthr[2], +OBJECT fthr[2], OBJECT *target, OBJECT *crs, BOOLEAN ok, BOOLEAN need_expand, +OBJECT *enclose, BOOLEAN fcr) +{ OBJECT y, tag, ylink, yield, ytag, zlink; + OBJECT res, z, firsttag, firstres; + + /* make sure left parameter (the tag) is in order */ + debug0(DOM, DD, " manifesting CASE now"); + Child(tag, Down(x)); + debug1(DOM, DD, " manifesting CASE tag %s now", EchoObject(tag)); + tag = Manifest(tag, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, + &nenclose, fcr); + tag = ReplaceWithTidy(tag, FALSE); + + /* make sure the right parameter is an ACAT */ + Child(y, LastDown(x)); + if( type(y) == YIELD ) + { New(z, ACAT); + MoveLink(Up(y), z, PARENT); + Link(x, z); + y = z; + } + if( type(y) != ACAT ) + { Error(8, 7, "%s deleted (right parameter is malformed)", + WARN, &fpos(y), KW_CASE); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + + /* hunt through right parameter for res, the selected case */ + res = nilobj; firsttag = nilobj; + for( ylink = Down(y); ylink != y && res == nilobj; ylink = NextDown(ylink) ) + { Child(yield, ylink); + if( type(yield) == GAP_OBJ ) continue; + if( type(yield) != YIELD ) + { Error(8, 8, "%s expected here", WARN, &fpos(yield), KW_YIELD); + break; + } + Child(ytag, Down(yield)); + ytag = Manifest(ytag, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, + &nenclose, fcr); + ytag = ReplaceWithTidy(ytag, FALSE); + if( is_word(type(ytag)) ) + { if( firsttag == nilobj ) + { firsttag = ytag; + Child(firstres, LastDown(yield)); + } + if( (is_word(type(tag)) && StringEqual(string(ytag), string(tag))) || + StringEqual(string(ytag), STR_ELSE) ) + { Child(res, LastDown(yield)); + break; + } + } + else if( type(ytag) == ACAT ) + { z = ytag; + for( zlink = Down(z); zlink != z; zlink = NextDown(zlink) ) + { Child(ytag, zlink); + if( type(ytag) == GAP_OBJ ) continue; + if( !is_word(type(ytag)) ) + { Error(8, 9, "error in left parameter of %s", + WARN, &fpos(ytag), KW_YIELD); + break; + } + if( firsttag == nilobj ) + { firsttag = ytag; + Child(firstres, LastDown(yield)); + } + if( (is_word(type(tag)) && StringEqual(string(ytag), string(tag))) + || StringEqual(string(ytag), STR_ELSE) ) + { Child(res, LastDown(yield)); + break; + } + } + } + else Error(8, 10, "error in left parameter of %s", + WARN, &fpos(ytag), KW_YIELD); + } + if( res == nilobj ) + { if( firsttag != nilobj ) + { Error(8, 11, "replacing unknown %s option %s by %s", + WARN, &fpos(tag), KW_CASE, string(tag), string(firsttag)); + res = firstres; + debug1(DGP, D, " res = %s", EchoObject(res)); + } + else + { Error(8, 12, "%s deleted (choice %s unknown)", + WARN, &fpos(tag), KW_CASE, string(tag)); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + } + + /* now manifest the result and replace x with it */ + DeleteLink(Up(res)); + ReplaceNode(res, x); + DisposeObject(x); + x = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; +} /* ManifestCase */ + + +/*@::ManifestTg@**************************************************************/ +/* */ +/* OBJECT ManifestTg(x,env,style,bthr, fthr, target, crs, ok, need_expand, */ +/* enclose, fcr) */ +/* */ +/* This procedure implements Manifest (see below) when x is TAGGED. */ +/* */ +/*****************************************************************************/ + +static OBJECT ManifestTg(OBJECT x, OBJECT env, STYLE *style, OBJECT bthr[2], +OBJECT fthr[2], OBJECT *target, OBJECT *crs, BOOLEAN ok, BOOLEAN need_expand, +OBJECT *enclose, BOOLEAN fcr) +{ OBJECT y, tag, z; + + /* make sure first argument is a cross-reference */ + assert( Down(x) != x && NextDown(Down(x)) != x && + NextDown(NextDown(Down(x))) == x, "Manifest TAGGED: children!" ); + Child(y, Down(x)); + if( !is_cross(type(y)) ) + { + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, TRUE); + if( !is_cross(type(y)) ) + { Error(8, 13, "left parameter of %s is not a cross reference", + WARN, &fpos(y), KW_TAGGED); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + } + + /* make sure the arguments of the cross-reference are OK */ + Child(z, Down(y)); + if( type(z) != CLOSURE ) + { Error(8, 14, "left parameter of %s must be a symbol", + WARN, &fpos(y), KW_TAGGED); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + if( !has_tag(actual(z)) ) + { Error(8, 15, "symbol %s not allowed here (it has no %s)", + WARN, &fpos(z), SymName(actual(z)), KW_TAG); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + Child(z, NextDown(Down(y))); + z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + z = ReplaceWithTidy(z, FALSE); + if( is_word(type(z)) && StringEqual(string(z), KW_PRECEDING) ) + cross_type(y) = CROSS_PREC; + else if( is_word(type(z)) && StringEqual(string(z), KW_FOLLOWING) ) + cross_type(y) = CROSS_FOLL; + else if( is_word(type(z)) && StringEqual(string(z), KW_FOLL_OR_PREC) ) + cross_type(y) = CROSS_FOLL_OR_PREC; + else + { Error(8, 16, "%s, %s or %s expected in left parameter of %s", + WARN, &fpos(z), KW_PRECEDING, KW_FOLLOWING, KW_FOLL_OR_PREC, KW_TAGGED); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + + /* make sure second argument (the new key) is ok */ + Child(tag, LastDown(x)); + tag = Manifest(tag, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + tag = ReplaceWithTidy(tag, TRUE); /* && */ + if( !is_word(type(tag)) ) + { Error(8, 17, "right parameter of %s must be a simple word", + WARN, &fpos(tag), KW_TAGGED); + ifdebug(DOM, DD, DebugObject(tag)); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + + /* assemble insinuated cross reference which replaces x */ + ReplaceNode(tag, z); + DisposeObject(z); + ReplaceNode(y, x); + DisposeObject(x); + x = y; + ReplaceWithSplit(x, bthr, fthr); + debug1(DCR, DD, " tagged manifesting %s", EchoObject(x)); + return x; +} /* end ManifestTg */ + + +/*@::ManifestCl@**************************************************************/ +/* */ +/* OBJECT ManifestCl(x,env,style,bthr, fthr, target, crs, ok, need_expand, */ +/* enclose, fcr) */ +/* */ +/* This procedure implements Manifest (see below) when x is CLOSURE. */ +/* */ +/*****************************************************************************/ + +static OBJECT ManifestCl(OBJECT x, OBJECT env, STYLE *style, OBJECT bthr[2], +OBJECT fthr[2], OBJECT *target, OBJECT *crs, BOOLEAN ok, BOOLEAN need_expand, +OBJECT *enclose, BOOLEAN fcr) +{ OBJECT y, link, sym, res_env, hold_env, hold_env2, z, newz, command; + BOOLEAN symbol_free; + + sym = actual(x); + StyleCopy(save_style(x), *style); + debugcond2(DOM, D, StringEqual(SymName(sym), "@Section"), + "manifesting %s at %s", SymName(sym), EchoFilePos(&fpos(x))); + debug1(DOM, DD, " [ manifesting closure %s", SymName(sym)); + + /* enclose, if required */ + if( *enclose != nilobj && (actual(x)==GalleySym || actual(x)==ForceGalleySym) ) + { OBJECT sym, par; + ReplaceNode(*enclose, x); + Child(sym, Down(*enclose)); + Child(par, Down(sym)); + DisposeChild(Down(par)); + Link(par, x); + x = *enclose; + *enclose = nilobj; + debug1(DHY, DD, " Manifest/enclose: %s", EchoObject(x)); + x = Manifest(x, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + debug0(DOM, DD, " ] returning from manifesting closure (enclose)"); + return x; + } + + /* expand parameters where possible, and find if they are all free */ + symbol_free = TRUE; + debugcond1(DOM, DD, indefinite(sym), " freeing %s", EchoObject(x)); + for( link = Down(x); link != x; link = NextDown(link) ) + { Child(y, link); + assert( type(y) == PAR, "Manifest/CLOSURE: type(y) != PAR!" ); + Child(z, Down(y)); + + /* try to evaluate the actual parameter z */ + if( !is_word(type(z)) && !has_par(actual(y)) ) + { + if( is_tag(actual(y)) || is_key(actual(y)) ) + { z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + z = ReplaceWithTidy(z, TRUE); + if( !is_word(type(z)) ) + { + debug2(ANY, D, "z = %s %s", Image(type(z)), EchoObject(z)); + Error(8, 41, "this %s is not a sequence of one or more words", FATAL, + &fpos(y), SymName(actual(y))); + } + } + else if( type(z) == NEXT ) + { z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + z = ReplaceWithTidy(z, FALSE); + } + else if( type(z) == CLOSURE && is_par(type(actual(z))) ) + { + /* see whether z would come to something simple if expanded */ + newz = ParameterCheck(z, env); + debugcond2(DOM, DD, indefinite(sym), " ParameterCheck(%s, env) = %s", + EchoObject(z), EchoObject(newz)); + if( newz != nilobj ) + { ReplaceNode(newz, z); + DisposeObject(z); + z = newz; + } + } + } + + /* now check z to see whether it is either a word or and ACAT of words */ + /* *** + if( type(z) == ACAT ) + { int i = 0; OBJECT t, tlink, g; + tlink = Down(z); + for( ; tlink != z && symbol_free; tlink = NextDown(tlink), i++ ) + { Child(t, tlink); + switch( type(t) ) + { + case WORD: + case QWORD: if( i > 20 ) symbol_free = FALSE; + break; + + case GAP_OBJ: if( Down(t) != t ) + { Child(g, Down(t)); + if( !is_word(type(g)) ) symbol_free = FALSE; + } + break; + + default: symbol_free = FALSE; + break; + + } + } + } + else + *** */ + + if( !is_word(type(z)) ) + { symbol_free = FALSE; + } + } + debugcond2(DOM, DD, indefinite(sym)," s_f = %s, x = %s", + bool(symbol_free), EchoObject(x)); + + /* if all parameters are free of symbols, optimize environment */ + if( symbol_free && imports(sym) == nilobj && enclosing(sym) != StartSym ) + { y = SearchEnv(env, enclosing(sym)); + if( y != nilobj && type(y) == CLOSURE ) + { OBJECT prntenv; + Parent(prntenv, Up(y)); + if( type(prntenv) != ENV ) fprintf(stderr, "%s\n", Image(type(prntenv))); + assert(type(prntenv) == ENV, "Manifest: prntenv!"); + if( Down(prntenv) == LastDown(prntenv) ) + { env = prntenv; + } + else + { debug0(DCR, DDD, "calling SetEnv from Manifest (a)"); + env = SetEnv(y, nilobj); + } + New(hold_env2, ACAT); Link(hold_env2, env); + } + else + { /* *** letting this through now + if( has_par(enclosing(sym)) ) + Error(8, 18, "symbol %s used outside %s", WARN, &fpos(x), SymName(sym), + SymName(enclosing(sym))); + *** */ + hold_env2 = nilobj; + } + } + else hold_env2 = nilobj; + + debug3(DOM, DD, " expansion: has_target %s, indefinite %s, recursive %s", + bool(has_target(sym)), bool(indefinite(sym)), bool(recursive(sym))); + if( has_target(sym) && !need_expand ) + { + /* convert symbols with targets to unsized galleys */ + OBJECT hd; + New(hd, HEAD); + FposCopy(fpos(hd), fpos(x)); + actual(hd) = sym; + limiter(hd) = opt_components(hd) = opt_constraints(hd) = nilobj; + gall_dir(hd) = horiz_galley(sym); + ready_galls(hd) = nilobj; + must_expand(hd) = TRUE; + sized(hd) = FALSE; + ReplaceNode(hd, x); + Link(hd, x); + AttachEnv(env, x); + SetTarget(hd); + enclose_obj(hd) = (has_enclose(sym) ? BuildEnclose(hd) : nilobj); + x = hd; + threaded(x) = bthr[COLM] != nilobj || fthr[COLM] != nilobj; + ReplaceWithSplit(x, bthr, fthr); + } + else if( + *target == sym ? (*target = nilobj, TRUE) : + need_expand ? TRUE : + uses_galley(sym) && !recursive(sym) ? TRUE : + !indefinite(sym) && !recursive(sym) ? TRUE : + indefinite(sym) && *target != nilobj ? SearchUses(sym, *target) + : FALSE + ) + { + /* expand the closure and manifest the result */ + debug1(DOM, DD, "expanding; style: %s", EchoStyle(style)); + debug0(DCE, DD, " calling ClosureExpand from Manifest/CLOSURE"); + /* *** now requesting cross refs always, not only if ok + x = ClosureExpand(x, env, ok, crs, &res_env); + *** */ + x = ClosureExpand(x, env, TRUE, crs, &res_env); + New(hold_env, ACAT); Link(hold_env, res_env); + debug1(DOM, DD, "recursive call; style: %s", EchoStyle(style)); + if( type(x) == FILTERED ) + { assert( type(sym) == RPAR, "ManifestCl/filtered: type(sym)!" ); + assert( filter(enclosing(sym)) != nilobj, "ManifestCl filter-encl!" ); + New(command, CLOSURE); + FposCopy(fpos(command), fpos(x)); + actual(command) = filter(enclosing(sym)); + FilterSetFileNames(x); + command = Manifest(command,env,style,nbt,nft,&ntarget,crs,FALSE,FALSE, &nenclose, fcr); + command = ReplaceWithTidy(command, TRUE); + if( !is_word(type(command)) ) + Error(8, 19, "filter parameter of %s symbol is not simple", + FATAL, &fpos(command), SymName(enclosing(sym))); + y = FilterExecute(x, string(command), res_env); + DisposeObject(command); + ReplaceNode(y, x); + DisposeObject(x); + x = y; + } + x = Manifest(x, res_env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + DisposeObject(hold_env); + } + else + { + AttachEnv(env, x); + threaded(x) = bthr[COLM] != nilobj || fthr[COLM] != nilobj; + debug0(DOM, DD, " closure; calling ReplaceWithSplit"); + ReplaceWithSplit(x, bthr, fthr); + } + if( hold_env2 != nilobj ) DisposeObject(hold_env2); + debug0(DOM, DD, " ] returning from manifesting closure"); + return x; +} /* end ManifestCl */ + + +/*@::Manifest()@**************************************************************/ +/* */ +/* OBJECT Manifest(x, env, style, bthr, fthr, target, crs, ok, need_expand, */ +/* enclose, fcr) */ +/* */ +/* Manifest object x, interpreted in environment env and style style. */ +/* The result replaces x, and is returned also. */ +/* The manifesting operation converts x from a pure parse tree object */ +/* containing closures and no threads, to an object ready for sizing, */ +/* with fonts propagated to the words, fill styles propagated to the */ +/* ACATs, and line spacings propagated to all interested parties. */ +/* All non-recursive, non-indefinite closures are expanded. */ +/* Threads joining objects on a mark are constructed, and SPLIT objects */ +/* inserted, so that sizing becomes a trivial operation. */ +/* */ +/* Manifest will construct threads and pass them up as children of bthr[] */ +/* and fthr[] whenever non-nilobj values of these variables are passed in: */ +/* */ +/* bthr[COLM] protrudes upwards from x */ +/* fthr[COLM] protrudes downwards from x */ +/* bthr[ROWM] protrudes leftwards from x */ +/* fthr[ROWM] protrudes rightwards from x */ +/* */ +/* If *target != nilobj, Manifest will expand indefinite closures leading */ +/* to the first @Galley lying within an object of type *target. */ +/* */ +/* If *target != nilobj and *enclose != nilobj, Manifest will enclose */ +/* any @Galley or @ForceGalley it comes across in *enclose. */ +/* */ +/* The env parameter contains the environment in which x is to be */ +/* evaluated. Environments are shared, so their correct disposal is not */ +/* simple. The rule is this: the code which creates an environment, or */ +/* detaches it, is responsible for holding it with a dummy parent until */ +/* it is no longer required. */ +/* */ +/* Some objects x are not "real" in the sense that they do not give rise */ +/* to rectangles in the final printed document. The left parameter of */ +/* @Wide and similar operators, and the gap following a concatenation */ +/* operator, are examples of such non-real objects. The ok flag is true */ +/* when x is part of a real object. This is needed because some things, */ +/* such as the insinuation of cross references, the breaking of */ +/* lines @Break ACAT objects, and conversion to small capitals, only apply */ +/* to real objects. */ +/* */ +/* If *crs != nilobj, it points to a list of indexes to cross-references */ +/* which are to be insinuated into the manifested form of x if x is real. */ +/* */ +/* If need_expand is TRUE it forces closure x to expand. */ +/* */ +/* If fcr is TRUE, the objective is to expand until a cross-reference is */ +/* the result; so expansion will stop at a CROSS or FORCE_CROSS object. */ +/* */ +/* A postcondition of Manifest() is that the underline() flag is set to */ +/* either UNDER_ON or UNDER_OFF in every WORD, every QWORD, and every child */ +/* of every ACAT, including the gaps. This can be verified by checking */ +/* that the WORD and QWORD cases set underline() to UNDER_OFF, and the ACAT */ +/* case sets every child of the ACAT to UNDER_OFF. To see that the correct */ +/* subset of these flags gets changed to UNDER_ON, consult SetUnderline(). */ +/* The underline() flag is undefined otherwise, and should have value */ +/* UNDER_UNDEF. */ +/* */ +/*****************************************************************************/ +#define MAX_DEPTH 500 + +OBJECT Manifest(OBJECT x, OBJECT env, STYLE *style, OBJECT bthr[2], +OBJECT fthr[2], OBJECT *target, OBJECT *crs, BOOLEAN ok, BOOLEAN need_expand, +OBJECT *enclose, BOOLEAN fcr) +{ OBJECT bt[2], ft[2], y, link, gaplink, g; register FULL_CHAR *p; + OBJECT res, res_env, res_env2, hold_env, hold_env2, z, prev; + OBJECT link1, link2, x1, x2, y1, y2; + int par, num1, num2; GAP res_gap; unsigned res_inc; STYLE new_style; + BOOLEAN done, multiline; FULL_CHAR ch; float scale_factor; + static int depth = 0; +#if DEBUG_ON + static unsigned int debug_type[MAX_DEPTH]; + static OBJECT debug_actual[MAX_DEPTH]; + static int debug_lnum[MAX_DEPTH]; + BOOLEAN eee = (*enclose != nilobj); + debug_type[depth] = type(x); + debug_lnum[depth] = line_num(fpos(x)); + if( type(x) == CLOSURE ) debug_actual[depth] = actual(x); + depth++; + if( depth == MAX_DEPTH ) + { Error(8, 20, "maximum depth of symbol expansion (%d) reached", + WARN, &fpos(x), MAX_DEPTH); + Error(8, 21, "the symbols currently being expanded are:", WARN, &fpos(x)); + while( --depth >= 0 ) + { + Error(8, 22, "at %d: %d %s %s", WARN, &fpos(x), depth, debug_lnum[depth], + Image(debug_type[depth]), debug_type[depth] == CLOSURE ? + FullSymName(debug_actual[depth], AsciiToFull(".")) : STR_EMPTY); + } + Error(8, 23, "exiting now", FATAL, &fpos(x)); + } +#else + depth++; + if( depth == MAX_DEPTH ) + { + Error(8, 40, "maximum depth of symbol expansion (%d) reached", + FATAL, &fpos(x), MAX_DEPTH); + } +#endif + + debug2(DOM, DD, "[Manifest(%s %s )", Image(type(x)), EchoObject(x)); + debug1(DOM, DD, " environment: %s", EchoObject(env)); + debug6(DOM, DD, " style: %s; target: %s; threads: %s%s%s%s", + EchoStyle(style), SymName(*target), + bthr[COLM] ? " up" : "", fthr[COLM] ? " down" : "", + bthr[ROWM] ? " left" : "", fthr[ROWM] ? " right" : ""); + debugcond2(DHY, DD, eee, "[ Manifest(%s, *enclose = %s)", + EchoObject(x), EchoObject(*enclose)); + + switch( type(x) ) + { + + case ENV_OBJ: + + debug0(DHY, DD, "[Manifest env_obj:"); + ifdebug(DHY, DD, DebugObject(x)); + Child(y, Down(x)); + Child(res_env, NextDown(Down(x))); + assert( type(res_env) == ENV, "Manifest/ENV_OBJ: res_env!"); + y = Manifest(y, res_env, style, bthr, fthr, target, crs, ok, TRUE, enclose, fcr); + /* we always expand children of ENV_OBJ (need_expand == TRUE) */ + ReplaceNode(y, x); + DisposeObject(x); + x = y; + debug1(DHY, DD, "]Manifest env_obj returning %s", EchoObject(x)); + break; + + + case CLOSURE: + + x = ManifestCl(x, env, style, bthr, fthr, target, crs, ok, need_expand, enclose, fcr); + break; + + + case PAGE_LABEL: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, TRUE); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case NULL_CLOS: + + StyleCopy(save_style(x), *style); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case CROSS: + case FORCE_CROSS: + + assert( Down(x) != x && LastDown(x) != Down(x), "Manifest: CROSS child!"); + if( !fcr ) /* stop if fcr, i.e. if purpose was to find a cross-reference */ + { + debug0(DCR, DD, " calling CrossExpand from Manifest/CROSS"); + Child(y, Down(x)); + if( type(y) == CLOSURE ) + { + /* *** want cross ref now always, not only if ok + x = CrossExpand(x, env, style, ok, crs, &res_env); + *** */ + x = CrossExpand(x, env, style, crs, &res_env); + assert( type(x) == CLOSURE, "Manifest/CROSS: type(x)!" ); + New(hold_env, ACAT); Link(hold_env, res_env); + /* expand here (calling Manifest immediately makes unwanted cr) */ + debug0(DCE, DD, " calling ClosureExpand from Manifest/CROSS"); + x = ClosureExpand(x, res_env, FALSE, crs, &res_env2); + New(hold_env2, ACAT); Link(hold_env2, res_env2); + x = Manifest(x, res_env2, style, bthr, fthr, target, crs, ok, TRUE, enclose, fcr); + DisposeObject(hold_env); + DisposeObject(hold_env2); + } + else + { y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); + DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + } + } + break; + + + case WORD: + case QWORD: + + if( !ok || *crs == nilobj ) + { word_font(x) = font(*style); + word_colour(x) = colour(*style); + word_language(x) = language(*style); + word_hyph(x) = hyph_style(*style) == HYPH_ON; + debug3(DOM, DDD, " manfifest/WORD underline() := %s for %s %s", + "UNDER_OFF", Image(type(x)), EchoObject(x)); + if( small_caps(*style) && ok ) x = MapSmallCaps(x, style); + underline(x) = UNDER_OFF; + ReplaceWithSplit(x, bthr, fthr); + break; + } + New(y, ACAT); + FposCopy(fpos(y), fpos(x)); + ReplaceNode(y, x); + Link(y, x); x = y; + /* NB NO BREAK! */ + + + case ACAT: + + StyleCopy(save_style(x), *style); + adjust_cat(x) = padjust(*style); + StyleCopy(new_style, *style); + padjust(new_style) = FALSE; + assert(Down(x) != x, "Manifest: ACAT!" ); + link = Down(x); Child(y, link); + assert( type(y) != GAP_OBJ, "Manifest ACAT: GAP_OBJ is first!" ); + multiline = FALSE; + + /* manifest first child and insert any cross references */ + if( is_word(type(y)) ) + { word_font(y) = font(*style); + word_colour(y) = colour(*style); + word_language(y) = language(*style); + word_hyph(y) = hyph_style(*style) == HYPH_ON; + if( small_caps(*style) && ok ) y = MapSmallCaps(y, style); + } + else y = Manifest(y, env, &new_style, nbt, nft, target, crs, ok, FALSE, enclose, fcr); + debug3(DOM, DDD, " manfifest/ACAT1 underline() := %s for %s %s", + "UNDER_OFF", Image(type(y)), EchoObject(y)); + underline(y) = UNDER_OFF; + /* ??? if( is_word(type(y)) ) */ + if( ok && *crs != nilobj ) + { + debug1(DCR, DD, " insinuating %s", EchoObject(*crs)); + TransferLinks(Down(*crs), *crs, link); + DisposeObject(*crs); + *crs = nilobj; + } + prev = y; + + /* manifest subsequent gaps and children */ + for( gaplink = Down(link); gaplink != x; gaplink = NextDown(link) ) + { + Child(g, gaplink); + assert( type(g) == GAP_OBJ, "Manifest ACAT: no GAP_OBJ!" ); + debug3(DOM, DDD, " manfifest/ACAT2 underline() := %s for %s %s", + "UNDER_OFF", Image(type(g)), EchoObject(g)); + underline(g) = UNDER_OFF; + link = NextDown(gaplink); + assert( link != x, "Manifest ACAT: GAP_OBJ is last!" ); + Child(y, link); + assert( type(y) != GAP_OBJ, "Manifest ACAT: double GAP_OBJ!" ); + + /* manifest the next child */ + debug1(DOM, DD, " in ACAT (3), style = %s", EchoStyle(style)); + if( is_word(type(y)) ) + { word_font(y) = font(*style); + word_colour(y) = colour(*style); + word_language(y) = language(*style); + word_hyph(y) = hyph_style(*style) == HYPH_ON; + if( small_caps(*style) && ok ) y = MapSmallCaps(y, style); + } + else y = Manifest(y, env, &new_style, nbt, nft, target, crs, ok, FALSE, enclose, fcr); + debug3(DOM, DDD, " manifest/ACAT3 underline() := %s for %s %s", + "UNDER_OFF", Image(type(y)), EchoObject(y)); + underline(y) = UNDER_OFF; + + /* manifest the gap object */ + if( Down(g) != g ) + { + /* explicit & operator whose value is the child of g */ + Child(z, Down(g)); + z = Manifest(z, env, &new_style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + z = ReplaceWithTidy(z, FALSE); + GetGap(z, style, &gap(g), &res_inc); + vspace(g) = hspace(g) = 0; + } + else + { + /* implicit & operator */ + GapCopy(gap(g), space_gap(*style)); + switch( space_style(*style) ) + { + case SPACE_LOUT: + + /* usual Lout spacing, the number of white space characters */ + width(gap(g)) = width(gap(g)) * (vspace(g) + hspace(g)); + break; + + + case SPACE_COMPRESS: + + /* either zero or one space */ + if( vspace(g) + hspace(g) == 0 ) + { width(gap(g)) = 0; + } + else + { /* else width is like one space, so OK as is */ + } + break; + + + case SPACE_SEPARATE: + + /* exactly one space always, so do nothing further */ + break; + + + case SPACE_TROFF: + + /* Lout spacing plus one extra space for sentence end at eoln */ + width(gap(g)) = width(gap(g)) * (vspace(g) + hspace(g)); + debugcond2(DLS, DD, vspace(g) > 0, " prev = %s %s", + Image(type(prev)), EchoObject(prev)); + if( vspace(g) > 0 ) + { + /* set z to the preceding object; may need to search ACATs! */ + z = prev; + while( type(z) == ACAT + || type(z) == ONE_COL || type(z) == ONE_ROW + || type(z) == HCONTRACT || type(z) == VCONTRACT ) + { Child(z, LastDown(z)); + } + + /* if preceding object is a word, check for end sentence */ + if( is_word(type(z)) ) + { + for( p = string(z); *p != '\0'; p++ ); + debug4(DLS, DD, " prev = %s, last = %c, LSE = %s, LWES = %s", + EchoObject(z), *(p-1), bool(LanguageSentenceEnds[*(p-1)]), + bool(LanguageWordEndsSentence(z, FALSE))); + if( p != string(z) && LanguageSentenceEnds[*(p-1)] + && LanguageWordEndsSentence(z, FALSE) ) + width(gap(g)) += width(space_gap(*style)); + } + } + break; + + + case SPACE_TEX: + + if( vspace(g) + hspace(g) == 0 ) + { + /* zero spaces gives zero result, as for compress above */ + width(gap(g)) = 0; + } + else + { + /* set z to the preceding object; may need to search ACATs! */ + z = prev; + while( type(z) == ACAT + || type(z) == ONE_COL || type(z) == ONE_ROW + || type(z) == HCONTRACT || type(z) == VCONTRACT ) + { Child(z, LastDown(z)); + } + + /* one extra space if preceding is word ending sentence */ + if( is_word(type(z)) ) + { + for( p = string(z); *p != '\0'; p++ ); + debug4(DLS, DD, " prev = %s, last = %c, LSE = %s, LWES = %s", + EchoObject(z), *(p-1), bool(LanguageSentenceEnds[*(p-1)]), + bool(LanguageWordEndsSentence(z, TRUE))); + if( p != string(z) && LanguageSentenceEnds[*(p-1)] + && LanguageWordEndsSentence(z, TRUE) ) + width(gap(g)) += width(space_gap(*style)); + } + } + break; + + + default: + + assert(FALSE, "Manifest: unexpected space_style!"); + break; + } + nobreak(gap(g)) = (width(gap(g)) == 0); + if( line_breaker(g) && is_definite(type(y)) ) multiline = TRUE; + } + debug1(DOM, DD, " in ACAT, gap = %s", EchoLength(width(gap(g)))); + + /* compress adjacent juxtaposed words of equal font, etc. */ + if( is_word(type(y)) && width(gap(g)) == 0 && nobreak(gap(g)) && + vspace(g)+hspace(g)==0 && + units(gap(g)) == FIXED_UNIT && mode(gap(g)) == EDGE_MODE && + prev != nilobj && is_word(type(prev)) && !mark(gap(g)) && + word_font(prev) == word_font(y) && + word_colour(prev) == word_colour(y) && + word_language(prev) == word_language(y) ) + /* no need to compare underline() since both are false */ + { unsigned typ; + assert( underline(prev) == UNDER_OFF, "Manifest/ACAT: underline(prev)!" ); + assert( underline(y) == UNDER_OFF, "Manifest/ACAT: underline(y)!" ); + if( StringLength(string(prev))+StringLength(string(y)) >= MAX_BUFF ) + Error(8, 24, "word %s%s is too long", + FATAL, &fpos(prev), string(prev), string(y)); + z = y; + typ = type(prev) == QWORD || type(y) == QWORD ? QWORD : WORD; + y = MakeWordTwo(typ, string(prev), string(y), &fpos(prev)); + word_font(y) = word_font(prev); + word_colour(y) = word_colour(prev); + word_language(y) = word_language(prev); + word_hyph(y) = word_hyph(prev); + underline(y) = UNDER_OFF; + debug3(DOM, DDD, " manifest/ACAT4 underline() := %s for %s %s", + "UNDER_OFF", Image(type(y)), EchoObject(y)); + MoveLink(link, y, CHILD); + DisposeObject(z); + DisposeChild(Up(prev)); + DisposeChild(gaplink); + } + prev = y; + + /* insinuate any cross-references */ + if( ok && *crs != nilobj ) + { + debug1(DCR, DD, " insinuating %s", EchoObject(*crs)); + TransferLinks(Down(*crs), *crs, link); + DisposeObject(*crs); + *crs = nilobj; + } + } + + /* implement FILL_OFF break option if required */ + if( ok && multiline && fill_style(*style) == FILL_UNDEF ) + Error(8, 25, "missing %s symbol or option", FATAL, &fpos(x), KW_BREAK); + if( ok && multiline && fill_style(*style) == FILL_OFF ) + { OBJECT prev_acat, new_acat; BOOLEAN jn; + + /* compress any ACAT children of ACAT x */ + for( link = x; NextDown(link) != x; link = NextDown(link) ) + { Child(y, NextDown(link)); + if( type(y) == ACAT ) + { TransferLinks(Down(y), y, NextDown(link)); + DisposeChild(Up(y)); + link = PrevDown(link); + } + } + + /* do line breaks now */ + prev_acat = x; + New(x, VCAT); + adjust_cat(x) = FALSE; + ReplaceNode(x, prev_acat); + Link(x, prev_acat); + FirstDefinite(prev_acat, link, y, jn); + if( link != prev_acat ) + { + NextDefiniteWithGap(prev_acat, link, y, g, jn); + while( link != prev_acat ) + { + if( mode(gap(g)) != NO_MODE && line_breaker(g) ) + { OBJECT glink = PrevDown(Up(g)); + debug2(DOM, DD, "lines gap just before definite %s at %s", + Image(type(y)), EchoFilePos(&fpos(y))); + MoveLink(NextDown(glink), x, PARENT); + GapCopy(gap(g), line_gap(*style)); + width(gap(g)) *= find_max(1, vspace(g)); + New(new_acat, ACAT); + adjust_cat(new_acat) = padjust(*style); + FposCopy(fpos(new_acat), fpos(g)); + if( hspace(g) > 0 ) + { z = MakeWord(WORD, STR_EMPTY, &fpos(g)); + word_font(z) = font(*style); + word_colour(z) = colour(*style); + word_language(z) = language(*style); + word_hyph(z) = hyph_style(*style) == HYPH_ON; + underline(z) = UNDER_OFF; + Link(new_acat, z); + New(z, GAP_OBJ); + hspace(z) = hspace(g); + vspace(z) = 0; + underline(z) = UNDER_OFF; + GapCopy(gap(z), space_gap(*style)); + width(gap(z)) *= hspace(z); + Link(new_acat, z); + } + TransferLinks(NextDown(glink), prev_acat, new_acat); + StyleCopy(save_style(new_acat), *style); + Link(x, new_acat); + prev_acat = new_acat; + glink = prev_acat; + } + NextDefiniteWithGap(prev_acat, link, y, g, jn); + } + } + + /* remove any singleton ACAT objects under x, if they are VCATs */ + for( link = Down(x); link != x; link = NextDown(link) ) + { Child(y, link); + if( type(y) == ACAT && Down(y) == LastDown(y) ) + { Child(z, Down(y)); + if( type(z) == VCAT ) + { MoveLink(link, z, CHILD); + DisposeObject(y); + } + } + } + } + + ReplaceWithSplit(x, bthr, fthr); + break; + + + case HCAT: + case VCAT: + + x = ManifestCat(x, env, style, bthr, fthr, target, crs, ok, need_expand, + enclose, fcr); + break; + + + case WIDE: + case HIGH: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, FALSE); + GetGap(y, style, &res_gap, &res_inc); + if( res_inc != GAP_ABS || mode(res_gap) != EDGE_MODE || + units(res_gap) != FIXED_UNIT ) + { Error(8, 26, "replacing invalid left parameter of %s by 2i", + WARN, &fpos(y), Image(type(x)) ); + units(res_gap) = FIXED_UNIT; + width(res_gap) = 2*IN; + } + SetConstraint(constraint(x), MAX_FULL_LENGTH, width(res_gap), MAX_FULL_LENGTH); + DisposeChild(Down(x)); + goto ETC; /* two cases down from here */ + + + case HSHIFT: + case VSHIFT: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, FALSE); + GetGap(y, style, &shift_gap(x), &res_inc); + shift_type(x) = res_inc; + if( mode(shift_gap(x)) != EDGE_MODE || + (units(shift_gap(x))!=FIXED_UNIT && units(shift_gap(x))!=NEXT_UNIT) ) + { Error(8, 27, "replacing invalid left parameter of %s by +0i", + WARN, &fpos(y), Image(type(x)) ); + shift_type(x) = GAP_INC; + units(shift_gap(x)) = FIXED_UNIT; + width(shift_gap(x)) = 0; + mode(shift_gap(x)) = EDGE_MODE; + } + DisposeChild(Down(x)); + goto ETC; /* next case down from here */ + + + case HCONTRACT: + case VCONTRACT: + case HLIMITED: + case VLIMITED: + case HEXPAND: + case VEXPAND: + case ONE_COL: + case ONE_ROW: + + ETC: + par = (type(x)==ONE_COL || type(x)==HEXPAND || type(x) == HCONTRACT || + type(x)==HLIMITED || type(x)==WIDE || type(x)==HSHIFT) ? COLM : ROWM; + Child(y, Down(x)); + + /* manifest the child, propagating perp threads and suppressing pars */ + bt[par] = ft[par] = nilobj; + bt[1-par] = bthr[1-par]; ft[1-par] = fthr[1-par]; + y = Manifest(y, env, style, bt, ft, target, crs, ok, FALSE, enclose, fcr); + + /* replace with split object if par threads needed */ + bt[par] = bthr[par]; ft[par] = fthr[par]; + bt[1-par] = ft[1-par] = nilobj; + ReplaceWithSplit(x, bt, ft); + break; + + + case HSPAN: + case VSPAN: + + ReplaceWithSplit(x, bthr, fthr); + break; + + + case ROTATE: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, FALSE); + GetGap(y, style, &res_gap, &res_inc); + if( res_inc != GAP_ABS || mode(res_gap) != EDGE_MODE || + units(res_gap) != DEG_UNIT ) + { Error(8, 28, "replacing invalid left parameter of %s by 0d", + WARN, &fpos(y), Image(type(x)) ); + units(res_gap) = DEG_UNIT; + width(res_gap) = 0; + } + sparec(constraint(x)) = width(res_gap); + DisposeChild(Down(x)); + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE,enclose,fcr); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case BACKGROUND: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE,enclose,fcr); + Child(y, LastDown(x)); + y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE,enclose,fcr); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case START_HVSPAN: + case START_HSPAN: + case START_VSPAN: + case HSCALE: + case VSCALE: + case HCOVER: + case VCOVER: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE,enclose,fcr); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case SCALE: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, FALSE); + if( is_word(type(y)) && StringEqual(string(y), STR_EMPTY) ) + { + /* missing scale factor, meaning to be inserted automatically */ + bc(constraint(x)) = fc(constraint(x)) = 0; /* work out later */ + } + else if( type(y) != ACAT ) + { + /* presumably one word, common factor for horizontal and vertical */ + scale_factor = GetScaleFactor(y); + bc(constraint(x)) = fc(constraint(x)) = scale_factor * SF; + } + else + { + /* get horizontal scale factor */ + Child(z, Down(y)); + scale_factor = GetScaleFactor(z); + bc(constraint(x)) = scale_factor * SF; + + /* get vertical scale factor */ + Child(z, LastDown(y)); + scale_factor = GetScaleFactor(z); + fc(constraint(x)) = scale_factor * SF; + } + DisposeChild(Down(x)); + Child(y, LastDown(x)); + y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE, enclose, fcr); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case KERN_SHRINK: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + Child(y, LastDown(x)); + y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE, enclose, fcr); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case YIELD: + + Error(8, 29, "%s not expected here", FATAL, &fpos(x), KW_YIELD); + break; + + + case RAW_VERBATIM: + case VERBATIM: + + Child(y, Down(x)); + y = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + DeleteLink(Down(x)); + MergeNode(y, x); x = y; + break; + + + case CASE: + + x = ManifestCase(x,env,style, bthr, fthr, target, crs, ok, need_expand, enclose, fcr); + break; + + + case BACKEND: + + res = MakeWord(WORD, BackEndWord, &fpos(x)); + ReplaceNode(res, x); + DisposeObject(x); + x = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + break; + + + case XCHAR: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, FALSE); + if( !is_word(type(y)) ) + { Error(8, 30, "%s dropped (parameter is not a simple word)", + WARN, &fpos(y), KW_XCHAR); + res = MakeWord(WORD, STR_EMPTY, &fpos(x)); + } + else if( (word_font(y) = font(*style)) == 0 ) + { Error(8, 31, "%s dropped (no current font at this point)", + WARN, &fpos(y), KW_XCHAR); + res = MakeWord(WORD, STR_EMPTY, &fpos(x)); + } + else + { ch = MapCharEncoding(string(y), FontMapping(word_font(y), &fpos(y))); + if( ch == '\0' ) + { type(y) = QWORD; + Error(8, 32, "%s dropped (character %s unknown in font %s)", + WARN, &fpos(y), KW_XCHAR, StringQuotedWord(y), + FontFamilyAndFace(word_font(y))); + res = MakeWord(WORD, STR_EMPTY, &fpos(x)); + } + else + { res = MakeWord(QWORD, STR_SPACE, &fpos(x)); + string(res)[0] = ch; + } + } + ReplaceNode(res, x); + DisposeObject(x); + x = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + break; + + + case CURR_LANG: + + if( language(*style) == 0 ) + { Error(8, 33, "no current language at this point, using %s", + WARN, &fpos(x), STR_NONE); + res = MakeWord(WORD, STR_NONE, &fpos(x)); + } + else res = MakeWord(WORD, LanguageString(language(*style)), &fpos(x)); + ReplaceNode(res, x); + DisposeObject(x); + x = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + break; + + + case CURR_FAMILY: + case CURR_FACE: + + if( font(*style) == 0 ) + { Error(8, 38, "no current font at this point, using %s", + WARN, &fpos(x), STR_NONE); + res = MakeWord(WORD, STR_NONE, &fpos(x)); + } + else if( type(x) == CURR_FAMILY ) + res = MakeWord(WORD, FontFamily(font(*style)), &fpos(x)); + else + res = MakeWord(WORD, FontFace(font(*style)), &fpos(x)); + ReplaceNode(res, x); + DisposeObject(x); + x = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + break; + + + case FONT: + case SPACE: + case YUNIT: + case ZUNIT: + case BREAK: + case COLOUR: + case LANGUAGE: + + assert( Down(x) != x && NextDown(Down(x)) != x, "Manifest: FONT!" ); + StyleCopy(new_style, *style); + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, type(x) == COLOUR); + switch( type(x) ) + { + case FONT: FontChange(&new_style, y); + break; + + case SPACE: SpaceChange(&new_style, y); + break; + + case YUNIT: YUnitChange(&new_style, y); + break; + + case ZUNIT: ZUnitChange(&new_style, y); + break; + + case BREAK: BreakChange(&new_style, y); + break; + + case COLOUR: ColourChange(&new_style, y); + break; + + case LANGUAGE: LanguageChange(&new_style, y); + break; + + } + DisposeChild(Down(x)); + Child(y, Down(x)); + y = Manifest(y, env, &new_style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + DeleteLink(Down(x)); + MergeNode(y, x); x = y; + break; + + + case PADJUST: + case HADJUST: + case VADJUST: + + StyleCopy(new_style, *style); + if( type(x) == VADJUST ) vadjust(new_style) = TRUE; + else if( type(x) == HADJUST ) hadjust(new_style) = TRUE; + else padjust(new_style) = TRUE; + Child(y, Down(x)); + y = Manifest(y, env, &new_style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + DeleteLink(Down(x)); + MergeNode(y, x); x = y; + break; + + + case UNDERLINE: + + /* change x to an ACAT and set the underline flags in its child */ + assert( Down(x) != x && NextDown(Down(x)) == x, "Manifest: UNDERLINE!" ); + type(x) = ACAT; + adjust_cat(x) = padjust(*style); + padjust(*style) = FALSE; + StyleCopy(save_style(x), *style); + Child(y, Down(x)); + y = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + SetUnderline(x); + break; + + + case MELD: + case COMMON: + case RUMP: + + assert( Down(x) != x && NextDown(Down(x)) != x, "Manifest: COMMON!" ); + debug2(DHY, DDD, "[Manifest %s %s", EchoObject(x), EchoObject(env)); + + /* find the first child of x, make sure it is an ACAT, and manifest */ + Child(x1, Down(x)); + if( type(x1) != ACAT ) + { OBJECT newx1; + New(newx1, ACAT); + adjust_cat(newx1) = padjust(*style); + padjust(*style) = FALSE; + MoveLink(Down(x), newx1, CHILD); + Link(newx1, x1); + x1 = newx1; + } + x1 = Manifest(x1, env, style, nbt, nft, target, crs, ok, FALSE, enclose, fcr); + link1 = x1; + while( NextDown(link1) != x1 ) + { Child(z, NextDown(link1)); + if( type(z) == ACAT ) + { TransferLinks(Down(z), z, NextDown(link1)); + DisposeChild(Up(z)); + } + else link1 = NextDown(link1); + } + debug1(DHY, DDD, " manifested x1 = %s", EchoObject(x1)); + + /* find the second child of x, make sure it is an ACAT, and manifest */ + Child(x2, NextDown(Down(x))); + if( type(x2) != ACAT ) + { OBJECT newx2; + New(newx2, ACAT); + adjust_cat(newx2) = padjust(*style); + padjust(*style) = FALSE; + MoveLink(NextDown(Down(x)), newx2, CHILD); + Link(newx2, x2); + x2 = newx2; + } + x2 = Manifest(x2, env, style, nbt, nft, target, crs, ok, FALSE, enclose, fcr); + link2 = x2; + while( NextDown(link2) != x2 ) + { Child(z, NextDown(link2)); + if( type(z) == ACAT ) + { TransferLinks(Down(z), z, NextDown(link2)); + DisposeChild(Up(z)); + } + else link2 = NextDown(link2); + } + debug1(DHY, DDD, " manifested x2 = %s", EchoObject(x2)); + + if( type(x) == MELD ) + { + /* if Meld, result is Meld(x1, x2) */ + res = Meld(x1, x2); + } + else + { + + /* find the point where x1 and x2 begin to differ */ + link1 = Down(x1); + link2 = Down(x2); + while( link1 != x1 && link2 != x2 ) + { + Child(y1, link1); + Child(y2, link2); + debug1(DHY, DDD, " y1 = %s", EchoObject(y1)); + debug1(DHY, DDD, " y2 = %s", EchoObject(y2)); + if( is_word(type(y1)) && is_word(type(y2)) ) + { + if( !StringEqual(string(y1), string(y2)) ) break; + } + else if( type(y1) != type(y2) ) break; + link1 = NextDown(link1); + link2 = NextDown(link2); + } + + /* if COMMON, result is x1 or x2 if either ran out, */ + /* or else x2 (say) up to but not including link2 and prec gap */ + if( type(x) == COMMON ) + { if( link2 == x2 ) + { res = x2; + } + else if( link1 == x1 ) + { res = x1; + } + else + { if( link2 == Down(x2) ) + res = MakeWord(WORD, STR_EMPTY, &fpos(x2)); + else + { TransferLinks(PrevDown(link2), x2, x1); + res = x2; + } + } + } + + /* if RUMP, result is x2 starting from link2 or NextDown(link2) */ + else if( type(x) == RUMP ) + { if( link2 == x2 ) + res = MakeWord(WORD, STR_EMPTY, &fpos(x2)); + else if( link1 == x1 ) + { + TransferLinks(Down(x2), NextDown(link2), x1); + res = x2; + } + else /* link1 != x1 */ + { + TransferLinks(Down(x2), link2, x1); + res = x2; + } + } + } + + /* now res replaces x */ + ReplaceNode(res, x); + DisposeObject(x); + x = res; + ReplaceWithSplit(x, bthr, fthr); + debug1(DHY, DDD, "]Manifest returning %s", EchoObject(x)); + break; + + + case INSERT: + + /* manifest and detach the left parameter, call it z */ + Child(z, Down(x)); + z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + DeleteLink(Down(x)); + + /* manifest the right parameter and make it the result */ + Child(y, LastDown(x)); + y = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + DeleteLink(LastDown(x)); + MergeNode(y, x); x = y; + + /* now find the reattachment point for z down inside the result, x */ + x = InsertObject(x, &z, style); + if( z != nilobj ) + { Error(8, 34, "object dropped by %s: no suitable insert point", WARN, + &fpos(x), KW_INSERT); + DisposeObject(z); + } + break; + + + case ONE_OF: + + Child(y, Down(x)); + if( type(y) != ACAT ) + { + /* child is not a sequence of choices, so ignore ONE_OF */ + Error(8, 39, "%s ignored: no choices in right parameter", WARN, + &fpos(x), KW_ONE_OF); + y = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, + enclose, fcr); + DeleteLink(Down(x)); + MergeNode(y, x); x = y; + } + else + { + /* try each child in turn; result is first to find *target */ + OBJECT target_before; + for( link = Down(y); link != y; link = NextDown(link) ) + { + Child(z, link); + if( type(z) == GAP_OBJ ) continue; + target_before = *target; + z = Manifest(z, env, style, bthr, fthr, target, crs, ok, FALSE, + enclose, fcr); + if( *target != target_before ) + break; + } + DeleteLink(Up(z)); + ReplaceNode(z, x); + DisposeObject(x); + x = z; + } + break; + + + case NEXT: + + assert( Down(x) != x, "Manifest/NEXT: Down(x) == x!" ); + Child(y, Down(x)); + debug1(DCS, DD, " Manifesting Next( %s, 1 )", EchoObject(y)); + y = Manifest(y, env, style, bthr, fthr, target, crs, FALSE, FALSE, enclose, fcr); + debug1(DCS, DD, " calling Next( %s, 1 )", EchoObject(y)); + done = FALSE; + y = Next(y, 1, &done); + debug2(DCS, DD, " Next(done = %s) returning %s", + bool(done), EchoObject(y)); + DeleteLink(Down(x)); + MergeNode(y, x); x = y; + break; + + + case PLUS: + case MINUS: + + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, FALSE); + Child(z, NextDown(Down(x))); + z = Manifest(z, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + z = ReplaceWithTidy(z, FALSE); + if( is_word(type(y)) && sscanf( (char *) string(y), "%d", &num1) == 1 && + is_word(type(z)) && sscanf( (char *) string(z), "%d", &num2) == 1 ) + { + FULL_CHAR buff[MAX_BUFF]; + sprintf( (char *) buff, "%d", type(x) == PLUS ? num1+num2 : num1-num2); + res = MakeWord(WORD, buff, &fpos(x)); + } + else + { res = MakeWord(WORD, STR_NOCROSS, &fpos(x)); + } + debug4(DOM, DD, "{ %s } %s { %s } = %s", EchoObject(y), Image(type(x)), + EchoObject(z), EchoObject(res)); + res = Manifest(res, env, style, bthr, fthr, target, crs, FALSE, FALSE, enclose, fcr); + ReplaceNode(res, x); + DisposeObject(x); + x = res; + break; + + + case OPEN: + + debug0(DCR, DD, " [ Manifest/OPEN begins:"); + Child(y, Down(x)); + DeleteLink(Down(x)); + Child(res, LastDown(x)); + hold_env = nilobj; + if( type(y) == CLOSURE ) + { AttachEnv(env, y); + StyleCopy(save_style(y), *style); + debug0(DCR, DDD, "calling SetEnv from Manifest (b)"); + res_env = SetEnv(y, nilobj); + New(hold_env, ACAT); Link(hold_env, res_env); + res = Manifest(res, res_env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + } + else if( is_cross(type(y)) ) + { Child(z, Down(y)); + if( type(z) == CLOSURE ) + { debug0(DCR, DD, " calling CrossExpand from Manifest/OPEN"); + /* *** want cross ref now always, not only if ok + y = CrossExpand(y, env, style, ok, crs, &res_env); + *** */ + y = CrossExpand(y, env, style, crs, &res_env); + AttachEnv(res_env, y); + debug0(DCR, DDD, "calling SetEnv from Manifest (c)"); + res_env = SetEnv(y, env); + New(hold_env, ACAT); Link(hold_env, res_env); + res = Manifest(res, res_env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + } + else + { Error(8, 35, "invalid left parameter of %s", WARN, &fpos(y), KW_OPEN); + res = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + } + } + else + { Error(8, 36, "invalid left parameter of %s", WARN, &fpos(y), KW_OPEN); + res = Manifest(res, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + } + ReplaceNode(res, x); + DisposeObject(x); + if( hold_env != nilobj ) DisposeObject(hold_env); + x = res; + debug0(DCR, DD, " ] Manifest/OPEN ends"); + break; + + + case TAGGED: + + x = ManifestTg(x, env, style, bthr, fthr, target, crs, ok, need_expand, enclose, fcr); + debug2(DCR, DD, "Manifest returning %ld %s", (long) x, EchoObject(x)); + break; + + + case PLAIN_GRAPHIC: + case GRAPHIC: + + debug1(DRS, DD, " graphic style in Manifest = %s", EchoStyle(style)); + Child(y, LastDown(x)); + y = Manifest(y, env, style, nbt, nft, target, crs, ok, FALSE, enclose, fcr); + StyleCopy(save_style(x), *style); + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + ReplaceWithSplit(x, bthr, fthr); + break; + + + case INCGRAPHIC: + case SINCGRAPHIC: + + StyleCopy(save_style(x), *style); + debug2(DGP, DD, " manifest at %s (style %s)", + EchoObject(x), EchoStyle(&save_style(x))); + Child(y, Down(x)); + y = Manifest(y, env, style, nbt, nft, &ntarget, crs, FALSE, FALSE, &nenclose, fcr); + y = ReplaceWithTidy(y, FALSE); + if( !is_word(type(y)) ) + { Error(8, 37, "%s deleted (invalid right parameter)", WARN, &fpos(y), + type(x) == INCGRAPHIC ? KW_INCGRAPHIC : KW_SINCGRAPHIC); + y = MakeWord(WORD, STR_EMPTY, &fpos(x)); + ReplaceNode(y, x); DisposeObject(x); + x = Manifest(y, env, style, bthr, fthr, target, crs, ok, FALSE, enclose, fcr); + return x; + } + ReplaceWithSplit(x, bthr, fthr); + break; + + + default: + + assert1(FALSE, "Manifest:", Image(type(x))); + break; + + } /* end switch */ + + debug2(DOM, DD, "]Manifest returning %s %s", Image(type(x)), EchoObject(x)); + debug1(DOM, DD, " at exit, style = %s", EchoStyle(style)); + debug1(DOM, DDD, "up: ", EchoObject(bthr[COLM])); + debug1(DOM, DDD, "down: ", EchoObject(fthr[COLM])); + debug1(DOM, DDD, "left: ", EchoObject(bthr[ROWM])); + debug1(DOM, DDD, "right: ", EchoObject(fthr[ROWM])); + debugcond1(DHY, DD, eee, "] Manifest returning %s", EchoObject(x)); + depth--; + return x; +} /* end Manifest */ |