/*@z18.c:Galley Transfer:Declarations@****************************************/ /* */ /* 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: z18.c */ /* MODULE: Galley Transfer */ /* EXTERNS: TransferInit(), TransferBegin(), TransferComponent(), */ /* TransferEnd(), TransferClose() */ /* */ /*****************************************************************************/ #include "externs.h" #define MAX_DEPTH 30 /* max depth of galleys */ static OBJECT root_galley = nilobj; /* the root galley */ static OBJECT targets[MAX_DEPTH]; /* currently open \Inputs */ static CONSTRAINT constraints[MAX_DEPTH]; /* their COLM constraints */ static int itop; /* stack top */ static CONSTRAINT initial_constraint; /* initial COLM constraint */ STYLE InitialStyle; /* initial style */ OBJECT InitialEnvironment; /* initial environment */ #if DEBUG_ON static void debug_targets(void) { int i; OBJECT tmp; for( i = 0; i <= itop; i++ ) { if( targets[i] == nilobj || Down(targets[i]) == targets[i] ) tmp = nilobj; else Child(tmp, Down(targets[i])); debug3(DGT, D, " target[%d] %s = %s", i, EchoConstraint(&constraints[i]), EchoObject(tmp)); } } /* end debug_targets */ #endif /*@::TransferInit()@**********************************************************/ /* */ /* TransferInit(InitEnv) */ /* */ /* Initialise this module. The initial environment is InitEnv. */ /* */ /*****************************************************************************/ void TransferInit(OBJECT InitEnv) { OBJECT dest, x, y, recs, inners, nothing, dest_index, up_hd, why; debug1(DGT, D, "[ TransferInit( %s )", EchoObject(InitEnv)); SetConstraint(initial_constraint, MAX_FULL_LENGTH-1, MAX_FULL_LENGTH-1, MAX_FULL_LENGTH-1); /* set initial environment and style */ InitialEnvironment = InitEnv; SetGap(line_gap(InitialStyle), FALSE,FALSE,FALSE,FIXED_UNIT,MARK_MODE,18*PT); vadjust(InitialStyle) = FALSE; hadjust(InitialStyle) = FALSE; padjust(InitialStyle) = FALSE; space_style(InitialStyle) = SPACE_LOUT; SetGap(space_gap(InitialStyle), FALSE,FALSE,TRUE,FIXED_UNIT,EDGE_MODE,1*EM); hyph_style(InitialStyle) = HYPH_UNDEF; fill_style(InitialStyle) = FILL_UNDEF; display_style(InitialStyle) = DISPLAY_UNDEF; small_caps(InitialStyle) = SMALL_CAPS_OFF; font(InitialStyle) = 0; /* i.e. undefined */ colour(InitialStyle) = 0; /* i.e. undefined */ language(InitialStyle) = 0; /* i.e. undefined */ yunit(InitialStyle) = 0; /* i.e. zero */ zunit(InitialStyle) = 0; /* i.e. zero */ nobreakfirst(InitialStyle) = FALSE; nobreaklast(InitialStyle) = FALSE; /* construct destination for root galley */ New(up_hd, HEAD); force_gall(up_hd) = FALSE; actual(up_hd) = enclose_obj(up_hd) = limiter(up_hd) = nilobj; opt_components(up_hd) = opt_constraints(up_hd) = nilobj; gall_dir(up_hd) = ROWM; New(dest_index, RECEIVING); New(dest, CLOSURE); actual(dest) = PrintSym; actual(dest_index) = dest; debug2(DGT, D, "TransferInit setting external_ver(%s %s) = TRUE", Image(type(dest)), SymName(actual(dest))); external_ver(dest) = TRUE; external_hor(dest) = FALSE; threaded(dest) = FALSE; blocked(dest_index) = FALSE; Link(up_hd, dest_index); /* construct root galley */ New(root_galley, HEAD); force_gall(root_galley) = FALSE; enclose_obj(root_galley) = limiter(root_galley) = nilobj; opt_components(root_galley) = opt_constraints(root_galley) = nilobj; gall_dir(root_galley) = ROWM; FposCopy(fpos(root_galley), *no_fpos); actual(root_galley) = whereto(root_galley) = nilobj; ready_galls(root_galley) = nilobj; must_expand(root_galley) = sized(root_galley) =FALSE; foll_or_prec(root_galley) = GALL_FOLL; New(x, CLOSURE); actual(x) = InputSym; Link(root_galley, x); SizeGalley(root_galley, InitEnv, TRUE, FALSE, FALSE, FALSE, &InitialStyle, &initial_constraint, nilobj, ¬hing, &recs, &inners, nilobj); assert( recs == nilobj , "TransferInit: recs != nilobj!" ); assert( inners == nilobj , "TransferInit: inners != nilobj!" ); Link(dest_index, root_galley); /* initialise target and constraint stacks */ Child(y, Down(root_galley)); assert( type(y) == RECEPTIVE && type(actual(y)) == CLOSURE && actual(actual(y)) == InputSym, "TransferInit: initial galley!" ); assert( external_ver(actual(y)), "TransferInit: input sym not external!" ); blocked(y) = TRUE; itop = 0; New(targets[itop], ACAT); Link(targets[itop], y); Constrained(actual(y), &constraints[itop], COLM, &why); debug2(DSC, DD, "Constrained( %s, COLM ) = %s", EchoObject(y), EchoConstraint(&constraints[itop])); debug0(DGT, D, "] TransferInit returning."); ifdebug(DGT, DD, debug_targets()); } /* end TransferInit */ /*@::TransferBegin()@*********************************************************/ /* */ /* OBJECT TransferBegin(x) */ /* */ /* Commence the transfer of a new galley whose header is invocation x. */ /* */ /*****************************************************************************/ OBJECT TransferBegin(OBJECT x) { OBJECT xsym, index, y, link, env, new_env, hold_env, res, hd, target, why; CONSTRAINT c; debug1(DGT, D, "[ [ TransferBegin( %s )", EchoObject(x)); ifdebug(DGT, DD, debug_targets()); assert( type(x) == CLOSURE, "TransferBegin: non-CLOSURE!" ); /* add an automatically generated @Tag parameter to x if required */ if( has_tag(actual(x)) ) CrossAddTag(x); /* construct new (inner) env chain */ if( Down(targets[itop]) == targets[itop] ) Error(18, 1, "cannot attach galley %s", FATAL,&fpos(x),SymName(actual(x))); Child(target, Down(targets[itop])); xsym = actual(x); env = GetEnv(actual(target)); debug1(DGT, DD, " current env chain: %s", EchoObject(env)); if( has_body(xsym) ) { /* prepare a copy of x for inclusion in environment */ y = CopyObject(x, no_fpos); /* attach its environment */ AttachEnv(env, y); /* now the new environment is y catenated with the old one */ debug0(DCR, DDD, "calling SetEnv from TransferBegin (a)"); new_env = SetEnv(y, nilobj); } else new_env = env; New(hold_env, ACAT); Link(hold_env, new_env); debug1(DGT, DD, " new env chain: %s", EchoObject(new_env)); /* convert x into an unsized galley called hd */ New(index, UNATTACHED); pinpoint(index) = nilobj; New(hd, HEAD); FposCopy(fpos(hd), fpos(x)); actual(hd) = xsym; limiter(hd) = opt_components(hd) = opt_constraints(hd) = nilobj; gall_dir(hd) = ROWM; ready_galls(hd) = nilobj; must_expand(hd) = TRUE; sized(hd) = FALSE; Link(index, hd); Link(hd, x); AttachEnv(env, x); SetTarget(hd); enclose_obj(hd) = (has_enclose(actual(hd)) ? BuildEnclose(hd) : nilobj); /* search for destination for hd and release it */ Link(Up(target), index); debug0(DGF,D, ""); debug1(DGF,D, " calling FlushGalley(%s) from TransferBegin, root_galley =", SymName(actual(hd))); ifdebug(DGF, D, DebugGalley(root_galley, nilobj, 4)); if( whereto(hd) == nilobj || !uses_extern_target(whereto(hd)) ) /* &&& */ FlushGalley(hd); /* if failed to flush, undo everything and exit */ Parent(index, Up(hd)); if( type(index) == UNATTACHED && !sized(hd) ) { DeleteNode(index); DisposeObject(hold_env); if( LastDown(x) != x ) { Child(env, LastDown(x)); if( type(env) == ENV ) DisposeChild(LastDown(x)); } debug1(DGT,D, "] TransferBegin returning failed, x: %s", EchoObject(x)); return x; } if( has_rpar(actual(hd)) ) { /* set up new target to be inner \InputSym, or nilobj if none */ if( ++itop >= MAX_DEPTH ) Error(18, 2, "galley nested too deeply (max is %d)", FATAL, &fpos(x), MAX_DEPTH); New(targets[itop], ACAT); target = nilobj; for( link = Down(hd); link != hd; link = NextDown(link) ) { Child(y, link); if( type(y) == RECEPTIVE && actual(actual(y)) == InputSym ) { Constrained(actual(y), &constraints[itop], COLM, &why); if( FitsConstraint(0, 0, constraints[itop]) ) { Link(targets[itop], y); target = y; debug2(DSC, DD, "Constrained( %s, COLM ) = %s", EchoObject(y), EchoConstraint(&constraints[itop])); env = DetachEnv(actual(y)); AttachEnv(new_env, actual(y)); } else { Error(18, 3, "galley %s deleted (insufficient width at target)", WARN, &fpos(hd), SymName(actual(hd))); } break; } } /* return a token appropriate to the new target */ if( target == nilobj || external_ver(actual(target)) ) res = NewToken(GSTUB_EXT, no_fpos, 0, 0, precedence(xsym), nilobj); else { Constrained(actual(target), &c, ROWM, &why); if( constrained(c) ) Error(18, 4, "right parameter of %s is vertically constrained", FATAL, &fpos(target), SymName(xsym)); else res = NewToken(GSTUB_INT, no_fpos, 0, 0, precedence(xsym), nilobj); } debug1(DGT, D, "] TransferBegin returning %s", Image(type(res))); } else { res = NewToken(GSTUB_NONE, no_fpos, 0, 0, precedence(xsym), nilobj); debug1(DGT, D, "] TransferBegin returning %s", Image(type(res))); } DisposeObject(hold_env); ifdebug(DGT, DD, debug_targets()); return res; } /* end TransferBegin */ /*@::TransferComponent()@*****************************************************/ /* */ /* TransferComponent(x) */ /* */ /* Transfer component x of a galley. */ /* */ /*****************************************************************************/ void TransferComponent(OBJECT x) { OBJECT y, env, start_search, recs, inners, nothing, hd, dest, dest_index; debug1(DGT, D, "[ TransferComponent( %s )", EchoObject(x)); ifdebug(DGT, DD, debug_targets()); /* if no dest_index, discard x and exit */ if( Down(targets[itop]) == targets[itop] ) { DisposeObject(x); debug0(DGT, D, "] TransferComponent returning (no target)."); return; } Child(dest_index, Down(targets[itop])); assert( external_ver(actual(dest_index)), "TransferComponent: internal!" ); /* make the component into a galley */ New(hd, HEAD); force_gall(hd) = FALSE; enclose_obj(hd) = limiter(hd) = nilobj; opt_components(hd) = opt_constraints(hd) = nilobj; gall_dir(hd) = ROWM; FposCopy(fpos(hd), fpos(x)); actual(hd) = whereto(hd) = ready_galls(hd) = nilobj; foll_or_prec(hd) = GALL_FOLL; must_expand(hd) = sized(hd) = FALSE; Link(hd, x); dest = actual(dest_index); env = GetEnv(dest); debug1(DGT, DD, " current env chain: %s", EchoObject(env)); SizeGalley(hd, env, TRUE, threaded(dest), FALSE, TRUE, &save_style(dest), &constraints[itop], nilobj, ¬hing, &recs, &inners, nilobj); if( recs != nilobj ) ExpandRecursives(recs); debug3(DSA, D, "after SizeGalley, hd width is (%s,%s), constraint was %s", EchoLength(back(hd, COLM)), EchoLength(fwd(hd, COLM)), EchoConstraint(&constraints[itop])); /* promote the components, remembering where old spot was */ start_search = PrevDown(Up(dest_index)); debug1(DSA, D, " calling AdjustSize from TransferComponent %s", EchoFilePos(&fpos(hd))); ifdebug(DSA, D, Child(y, Down(hd)); while( type(y) == VCAT ) Child(y, Down(y)); debug2(DSA, D, " first component is %s at %s", Image(type(y)), EchoFilePos(&fpos(y))); if( NextDown(Down(hd)) != hd && NextDown(NextDown(Down(hd))) != hd ) { Child(y, NextDown(NextDown(Down(hd)))); debug2(DSA, D, " second component is %s at %s", Image(type(y)), EchoFilePos(&fpos(y))); } ); AdjustSize(dest, back(hd, COLM), fwd(hd, COLM), COLM); Promote(hd, hd, dest_index, FALSE); DeleteNode(hd); /* flush any widowed galleys attached to \Input */ if( Down(dest_index) != dest_index ) { OBJECT tinners, index; New(tinners, ACAT); while( Down(dest_index) != dest_index ) { Child(y, Down(dest_index)); assert( type(y) == HEAD, "TransferComponent: input child!" ); if( opt_components(y) != nilobj ) { DisposeObject(opt_components(y)); opt_components(y) = nilobj; debug1(DOG, D, "TransferComponent de-optimizing %s (@Input case)", SymName(actual(y))); } DetachGalley(y); Parent(index, Up(y)); MoveLink(Up(index), NextDown(start_search), PARENT); Link(tinners, index); } debug0(DGF, D, " calling FlushInners() from TransferComponent (a)"); FlushInners(tinners, nilobj); } /* flush any galleys inside hd */ if( inners != nilobj ) { debug0(DGF, D, " calling FlushInners() from TransferComponent (b)"); FlushInners(inners, nilobj); } /* flush parent galley, if needed */ if( blocked(dest_index) ) { blocked(dest_index) = FALSE; Parent(y, Up(dest_index)); debug0(DGF, D, " calling FlushGalley from TransferComponent"); FlushGalley(y); } debug0(DGT, D, "] TransferComponent returning."); ifdebug(DGT, DD, debug_targets()); } /* end TransferComponent */ /*@::TransferEnd()@***********************************************************/ /* */ /* TransferEnd(x) */ /* */ /* End the transfer of a galley. */ /* */ /*****************************************************************************/ void TransferEnd(OBJECT x) { OBJECT recs, inners, nothing, z, env, dest, hd, dest_index, y, start_search; debug1(DGT, D, "[ TransferEnd( %s )", EchoObject(x)); ifdebug(DGT, DD, debug_targets()); /* if no dest_index, discard x and exit */ if( Down(targets[itop]) == targets[itop] ) { DisposeObject(x); DisposeObject(targets[itop--]); debug0(DGT, D, "] TransferEnd returning: no dest_index"); return; } Child(dest_index, Down(targets[itop])); /* make the component into a galley */ New(hd, HEAD); FposCopy(fpos(hd), fpos(x)); force_gall(hd) = FALSE; enclose_obj(hd) = limiter(hd) = nilobj; opt_components(hd) = opt_constraints(hd) = nilobj; gall_dir(hd) = ROWM; actual(hd) = whereto(hd) = ready_galls(hd) = nilobj; foll_or_prec(hd) = GALL_FOLL; must_expand(hd) = sized(hd) = FALSE; Link(hd, x); dest = actual(dest_index); env = GetEnv(dest); debug1(DGT, DD, " current env chain: %s", EchoObject(env)); SizeGalley(hd, env, external_ver(dest), threaded(dest), FALSE, TRUE, &save_style(dest), &constraints[itop], nilobj, ¬hing, &recs, &inners, nilobj); if( recs != nilobj ) ExpandRecursives(recs); debug3(DSA, D, "after SizeGalley, hd width is (%s,%s), constraint was %s", EchoLength(back(hd, COLM)), EchoLength(fwd(hd, COLM)), EchoConstraint(&constraints[itop])); /* promote the components, remembering where old spot was */ start_search = PrevDown(Up(dest_index)); debug0(DSA, D, "calling AdjustSize from TransferEnd (a)"); AdjustSize(dest, back(hd, COLM), fwd(hd, COLM), COLM); if( !external_ver(dest) ) { Child(z, LastDown(hd)); debug0(DSA, D, "calling AdjustSize from TransferEnd (b)"); AdjustSize(dest, back(z, ROWM), fwd(z, ROWM), ROWM); Interpose(dest, VCAT, hd, z); } Promote(hd, hd, dest_index, TRUE); DeleteNode(hd); /* flush any widowed galleys attached to \Input */ if( Down(dest_index) != dest_index ) { OBJECT tinners, index; New(tinners, ACAT); while( Down(dest_index) != dest_index ) { Child(y, Down(dest_index)); assert( type(y) == HEAD, "TransferEnd: input child!" ); if( opt_components(y) != nilobj ) { DisposeObject(opt_components(y)); opt_components(y) = nilobj; debug1(DOG, D, "TransferEnd de-optimizing %s (@Input case)", SymName(actual(y))); } DetachGalley(y); Parent(index, Up(y)); MoveLink(Up(index), NextDown(start_search), PARENT); Link(tinners, index); } debug0(DGF, D, " calling FlushInners() from TransferEnd (a)"); FlushInners(tinners, nilobj); } /* flush any galleys inside hd */ if( inners != nilobj ) { debug0(DGF, D, " calling FlushInners() from TransferEnd (b)"); FlushInners(inners, nilobj); } /* close dest_index, and flush parent galley if needed */ if( blocked(dest_index) ) { Parent(y, Up(dest_index)); DeleteNode(dest_index); debug0(DGF, D, " calling FlushGalley from TransferEnd"); FlushGalley(y); } else DeleteNode(dest_index); /* pop target stack and exit */ DisposeObject(targets[itop--]); debug0(DGT, D, "] ] TransferEnd returning."); ifdebug(DGT, DD, debug_targets()); } /* end TransferEnd */ /*@::TransferClose()@*********************************************************/ /* */ /* TransferClose() */ /* */ /* Close this module. */ /* */ /*****************************************************************************/ void TransferClose(void) { OBJECT inners; debug0(DGT, D, "[ TransferClose()"); ifdebug(DGT, DD, debug_targets()); debug0(DGA, D, " calling FreeGalley from TransferClose"); if( LastDown(root_galley) != root_galley ) { inners = nilobj; FreeGalley(root_galley, root_galley, &inners, nilobj, nilobj); if( inners != nilobj ) { debug0(DGF, D, " calling FlushInners() from TransferClose"); FlushInners(inners, nilobj); } debug0(DGF, D, " calling FlushGalley from TransferClose"); FlushGalley(root_galley); } debug0(DGT, D, "] TransferClose returning."); }