home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / lout2.lzh / LOUT2 / z20.c < prev    next >
Text File  |  1994-01-23  |  23KB  |  585 lines

  1. /*@z20.c:Galley Flushing:ParentFlush()@***************************************/
  2. /*                                                                           */
  3. /*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
  4. /*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
  5. /*                                                                           */
  6. /*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
  7. /*  Basser Department of Computer Science                                    */
  8. /*  The University of Sydney 2006                                            */
  9. /*  AUSTRALIA                                                                */
  10. /*                                                                           */
  11. /*  This program is free software; you can redistribute it and/or modify     */
  12. /*  it under the terms of the GNU General Public License as published by     */
  13. /*  the Free Software Foundation; either version 1, or (at your option)      */
  14. /*  any later version.                                                       */
  15. /*                                                                           */
  16. /*  This program is distributed in the hope that it will be useful,          */
  17. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  18. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  19. /*  GNU General Public License for more details.                             */
  20. /*                                                                           */
  21. /*  You should have received a copy of the GNU General Public License        */
  22. /*  along with this program; if not, write to the Free Software              */
  23. /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
  24. /*                                                                           */
  25. /*  FILE:         z20.c                                                      */
  26. /*  MODULE:       Galley Flushing                                            */
  27. /*  EXTERNS:      FlushGalley()                                              */
  28. /*                                                                           */
  29. /*****************************************************************************/
  30. #include "externs"
  31.  
  32.  
  33. /*****************************************************************************/
  34. /*                                                                           */
  35. /*  ParentFlush(dest_index, kill)                                            */
  36. /*                                                                           */
  37. /*  Flush the galley which is the parent of dest_index, if likely to flush.  */
  38. /*  If kill is TRUE, delete dest_index.                                      */
  39. /*                                                                           */
  40. /*****************************************************************************/
  41.  
  42. #define ParentFlush(dest_index, kill)                    \
  43. if( prnt_flush )                            \
  44. { debug0(DGF,D, "  ParentFlush calling FlushGalley (prnt)");        \
  45.   Parent(prnt, Up(dest_index));                        \
  46.   if( kill )  DeleteNode(dest_index);                    \
  47.   debug0(DGF, D, "  calling FlushGalley from ParentFlush");        \
  48.   FlushGalley(prnt);                            \
  49.   prnt_flush = FALSE;                            \
  50. }                                    \
  51. else if( kill )  DeleteNode(dest_index)
  52.  
  53.  
  54. /*@::FlushGalley()@***********************************************************/
  55. /*                                                                           */
  56. /*  FlushGalley(hd)                                                          */
  57. /*                                                                           */
  58. /*  Flush galley hd as far as possible.  It could be the root galley.        */
  59. /*                                                                           */
  60. /*****************************************************************************/
  61.  
  62. FlushGalley(hd)
  63. OBJECT hd;
  64. { OBJECT dest;            /* the target galley hd empties into         */
  65.   OBJECT dest_index;        /* the index of dest                         */
  66.   OBJECT inners;        /* list of galleys and PRECEDES to flush     */
  67.   OBJECT link, y;        /* for scanning through the components of hd */
  68.  
  69.   CONSTRAINT dest_constraint;    /* the vertical size constraint on dest      */
  70.   int f;            /* candidate replacement value for dest_fwd  */
  71.  
  72.   OBJECT dest_encl;        /* the VCAT enclosing dest, if any           */
  73.   int    dest_side;        /* if dest_encl != nil, the side dest is on  */
  74.   BOOLEAN need_adjust;        /* TRUE as soon as dest_encl needs adjusting */
  75.   LENGTH dest_back, dest_fwd;    /* the current size of dest_encl or dest     */
  76.   LENGTH frame_size;        /* the total constraint of dest_encl         */
  77.   OBJECT prec_gap;        /* the gap preceding dest, if any, else nil  */
  78.   OBJECT prec_def;        /* the component preceding dest, if any      */
  79.   OBJECT succ_gap;        /* the gap following dest, if any, else nil  */
  80.   OBJECT succ_def;        /* the component following dest, if any      */
  81.   OBJECT stop_link;        /* most recently seen gap link of hd         */
  82.   BOOLEAN prnt_flush;        /* TRUE when the parent of hd needs a flush  */
  83.   OBJECT zlink, z, tmp, prnt;
  84.  
  85.   debug1(DGF, D, "[ FlushGalley %s (hd)", SymName(actual(hd)));
  86.   prnt_flush = FALSE;
  87.  
  88.   RESUME:
  89.   assert( type(hd) == HEAD, "FlushGalley: type(hd) != HEAD!" );
  90.   debug1(DGF, D, "  resuming FlushGalley %s, hd =", SymName(actual(hd)));
  91.   ifdebug(DGF, DD, DebugObject(hd));
  92.   assert( Up(hd) != hd, "FlushGalley: resume found no parent to hd!" );
  93.  
  94.  
  95.   /*@@************************************************************************/
  96.   /*                                                                         */
  97.   /*  The first step is to examine the parent of galley hd to determine the  */
  98.   /*  status of the galley.  If this is not suitable for flushing, we do     */
  99.   /*  what we can to change the status.  If still no good, return; so if     */
  100.   /*  this code does not return, then the galley is ready to flush into a    */
  101.   /*  destination in the normal way, and the following variables are set:    */
  102.   /*                                                                         */
  103.   /*     dest_index   the parent of the galley and index of its destination  */
  104.   /*     dest         the destination of the galley, a @Galley object        */
  105.   /*                                                                         */
  106.   /***************************************************************************/
  107.  
  108.   Parent(dest_index, Up(hd));
  109.   switch( type(dest_index) )
  110.   {
  111.  
  112.     case DEAD:
  113.     
  114.       /* the galley has been killed off while this process was sleeping */
  115.       debug1(DGF, D, "] FlushGalley %s returning (DEAD)", SymName(actual(hd)));
  116.       debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  117.       return;
  118.  
  119.  
  120.     case UNATTACHED:
  121.     
  122.       /* the galley is currently not attached to a destination */
  123.       AttachGalley(hd, &inners);
  124.       Parent(dest_index, Up(hd));
  125.       if( type(dest_index)!=RECEIVING || actual(actual(dest_index))==InputSym )
  126.       {    if( type(dest_index) != DEAD )
  127.     { ParentFlush(dest_index, FALSE);
  128.       if( inners != nil ) FlushInners(inners, nil);
  129.     }
  130.     debug1(DGF,D,"] FlushGalley %s retn, no attach", SymName(actual(hd)));
  131.     debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  132.     return;
  133.       }
  134.  
  135.       /* if hd is a forcing galley, close all predecessors */
  136.       if( actual(hd) != nil && force_target(actual(hd)) )
  137.       {    Parent(prnt, Up(dest_index));
  138.     debug0(DGA, DD, "  force: prnt =");
  139.     ifdebug(DGA, DD, DebugObject(prnt));
  140.     debug1(DGA, D,"  calling FreeGalley from FlushGalley(%s)",
  141.       SymName(actual(hd)));
  142.     FreeGalley(prnt, Up(dest_index), &inners, Up(dest_index), whereto(hd));
  143.     prnt_flush = TRUE;
  144.     debug0(DGA, DD, "  force: after FreeGalley, prnt =");
  145.     ifdebug(DGA, DD, DebugObject(prnt));
  146.       }
  147.       else prnt_flush = prnt_flush || blocked(dest_index);
  148.       debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  149.  
  150.       if( inners != nil ) FlushInners(inners, nil);
  151.       goto RESUME;
  152.       break;
  153.  
  154.  
  155.     case RECEIVING:
  156.     
  157.       if( actual(actual(dest_index)) == InputSym )
  158.       { ParentFlush(dest_index, FALSE);
  159.     debug1(DGF, D, "] FlushGalley %s retn, input", SymName(actual(hd)));
  160.     debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  161.     return;
  162.       }
  163.       break;
  164.  
  165.  
  166.     default:
  167.     
  168.       Error(INTERN, &fpos(hd), "FlushGalley: %s ind!", Image(type(dest_index)));
  169.       break;
  170.   }
  171.   dest = actual(dest_index);
  172.   debug1(DGF, DD, "  dest_index: %s", EchoObject(dest_index));
  173.  
  174.  
  175.   /*@@************************************************************************/
  176.   /*                                                                         */
  177.   /*  The second step is to examine the components of the galley one by one  */
  178.   /*  to determine if they can be promoted.  Each component has the format   */
  179.   /*                                                                         */
  180.   /*    { <index> } <object>                                                 */
  181.   /*                                                                         */
  182.   /*  and is always followed by a gap object (except the last component).    */
  183.   /*  An index indicates that the following object has some interesting      */
  184.   /*  feature, and it points to that feature inside the object.  There are   */
  185.   /*  two possible actions for each component, in addition to accepting it:  */
  186.   /*                                                                         */
  187.   /*    REJECT:   The component does not fit, so detach the galley           */
  188.   /*    SUSPEND:  The component is incomplete; go to sleep and wait          */
  189.   /*                                                                         */
  190.   /***************************************************************************/
  191.  
  192.   stop_link = dest_encl = inners = nil;
  193.   need_adjust = FALSE;
  194.  
  195.   /***************************************************************************/
  196.   /*                                                                         */
  197.   /*  Loop invariant                                                         */
  198.   /*                                                                         */
  199.   /*  The children of hd up to but not including Child(link) have been       */
  200.   /*  examined and pronounced to be promotable.                              */
  201.   /*                                                                         */
  202.   /*  stop_link is the link of the most recently encountered gap object of   */
  203.   /*  hd, or nil if no gap object has been encountered yet.                  */
  204.   /*                                                                         */
  205.   /*  if dest_encl is non-nil, then the destination is not external,         */
  206.   /*  dest_encl is its parent, and the following variables are defined:      */
  207.   /*                                                                         */
  208.   /*    prec_gap         gap object preceding dest (which must exist)        */
  209.   /*    prec_def         first definite object preceding dest (must exist)   */
  210.   /*    dest_back        back(dest_encl) including effect of accepted compts */
  211.   /*    dest_fwd         fwd(dest_encl) including effect of accepted compts  */
  212.   /*    dest_side        BACK or FWD, i.e. which side of the mark dest is on */
  213.   /*    dest_constraint  the size constraint on dest                         */
  214.   /*    frame_size       size of frame enclosing dest_encl                   */
  215.   /*                                                                         */
  216.   /*  if dest_encl is nil, these variables are not defined.                  */
  217.   /*                                                                         */
  218.   /*  need_adjust is true if at least one definite component has been        */
  219.   /*  accepted for promotion and the destination is internal; hence,         */
  220.   /*  dest_encl is defined and its size needs to be adjusted.                */
  221.   /*                                                                         */
  222.   /*  inners is the set of all PRECEDES and UNATTACHED indexes found.        */
  223.   /*                                                                         */
  224.   /***************************************************************************/
  225.  
  226.   for( link = Down(hd);  link != hd;  link = NextDown(link) )
  227.   {
  228.     Child(y, link);
  229.     if( type(y) == SPLIT )  Child(y, DownDim(y, ROW));
  230.     debug1(DGF, DD, "  try to flush %s", EchoObject(y));
  231.     switch( type(y) )
  232.     {
  233.  
  234.       case GAP_OBJ:
  235.  
  236.     prec_gap = y;
  237.     stop_link = link;
  238.     if( !join(gap(y)) )  seen_nojoin(hd) = TRUE;
  239.     break;
  240.  
  241.  
  242.       case EXPAND_IND:
  243.       case GALL_PREC:
  244.       case GALL_FOLL:
  245.       case GALL_TARG:
  246.       case CROSS_PREC:
  247.       case CROSS_FOLL:
  248.       case CROSS_TARG:
  249.  
  250.     break;
  251.  
  252.  
  253.       case PRECEDES:
  254.       case UNATTACHED:
  255.       
  256.     if( inners == nil )  inners = New(ACAT);
  257.     Link(inners, y);
  258.     break;
  259.  
  260.  
  261.       case RECEIVING:
  262.       case RECEPTIVE:
  263.       
  264.     goto SUSPEND;
  265.  
  266.  
  267.       case FOLLOWS:
  268.       
  269.     Child(tmp, Down(y));
  270.     if( Up(tmp) == LastUp(tmp) )
  271.     { link = PrevDown(link);
  272.       DisposeChild(NextDown(link));
  273.       break;
  274.     }
  275.     Parent(tmp, Up(tmp));
  276.     assert(type(tmp) == PRECEDES, "Flush: PRECEDES!");
  277.     switch( CheckConstraint(tmp, dest_index) )
  278.     {
  279.       case CLEAR:    DeleteNode(tmp);
  280.             link = PrevDown(link);
  281.             DisposeChild(NextDown(link));
  282.             break;
  283.  
  284.       case PROMOTE:    break;
  285.  
  286.       case BLOCK:    goto SUSPEND;
  287.  
  288.       case CLOSE:    goto REJECT;
  289.     }
  290.     break;
  291.  
  292.  
  293.       case WORD:
  294.       case QWORD:
  295.       case ONE_COL:
  296.       case ONE_ROW:
  297.       case WIDE:
  298.       case HIGH:
  299.       case HSCALE:
  300.       case VSCALE:
  301.       case HCONTRACT:
  302.       case VCONTRACT:
  303.       case HEXPAND:
  304.       case VEXPAND:
  305.       case PADJUST:
  306.       case HADJUST:
  307.       case VADJUST:
  308.       case ROTATE:
  309.       case SCALE:
  310.       case INCGRAPHIC:
  311.       case SINCGRAPHIC:
  312.       case GRAPHIC:
  313.       case ACAT:
  314.       case HCAT:
  315.       case ROW_THR:
  316.       case CLOSURE:
  317.       case NULL_CLOS:
  318.       case CROSS:
  319.  
  320.     /* make sure y is not joined to a target below */
  321.     for( zlink = NextDown(link); zlink != hd; zlink = NextDown(zlink) )
  322.     { Child(z, zlink);
  323.       switch( type(z) )
  324.       {
  325.         case RECEPTIVE:
  326.         case RECEIVING:    y = z;
  327.                 goto SUSPEND;
  328.                 break;
  329.  
  330.         case GAP_OBJ:    if( !join(gap(z)) )  zlink = PrevDown(hd);
  331.                 break;
  332.  
  333.         default:        break;
  334.       }
  335.     }
  336.  
  337.     /* check size constraint */
  338.     if( !external(dest) )
  339.     {
  340.       /* initialise dest_encl etc if not done yet */
  341.       if( dest_encl == nil )
  342.       { assert( UpDim(dest,COL) == UpDim(dest,ROW), "FlushG: UpDims!" );
  343.         Parent(dest_encl, NextDown(Up(dest)));
  344.         assert( type(dest_encl) == VCAT, "FlushGalley: dest != VCAT!" );
  345.         SetNeighbours(Up(dest), FALSE, &prec_gap, &prec_def,
  346.           &succ_gap, &succ_def, &dest_side);
  347.         assert(prec_gap != nil || is_indefinite(type(y)),
  348.           "FlushGalley: prec_gap == nil && !is_indefinite(type(y))!" );
  349.         assert(succ_gap == nil, "FlushGalley: succ_gap != nil!" );
  350.         assert(dest_side == FWD || is_indefinite(type(y)),
  351.           "FlushGalley: dest_side != FWD || !is_indefinite(type(y))!");
  352.         dest_back = back(dest_encl, ROW);
  353.         dest_fwd  = fwd(dest_encl, ROW);
  354.         Constrained(dest_encl, &dest_constraint, ROW);
  355.         frame_size = constrained(dest_constraint) ? bfc(dest_constraint) :0;
  356.       }
  357.  
  358.       if( !is_indefinite(type(y)) )
  359.       { /* calculate effect of adding y to dest */
  360.         f = dest_fwd  + fwd(y, ROW) - fwd(prec_def, ROW) +
  361.           ActualGap(fwd(prec_def, ROW), back(y, ROW),
  362.             fwd(y, ROW), &gap(prec_gap), frame_size,
  363.             dest_back + dest_fwd - fwd(prec_def, ROW));
  364.         debug3(DGF, DD, "  b,f: %s,%s;   dest_encl: %s",
  365.             EchoLength(dest_back), EchoLength(f),
  366.             EchoConstraint(&dest_constraint));
  367.  
  368.         /* check new size against constraint */
  369.         if( !FitsConstraint(dest_back,f,dest_constraint) )
  370.           goto REJECT;
  371.         if( units(gap(prec_gap))==FRAME_UNIT && width(gap(prec_gap)) > FR )
  372.           goto REJECT;
  373.  
  374.         /* accept component */
  375.         dest_fwd = f;  prec_def = y;
  376.         need_adjust = TRUE;
  377.       }
  378.  
  379.     } /* end if( !external(dest) ) */
  380.  
  381.     /* accept this component into dest */
  382.     debug1(DGF, D, "  accept %s", EchoObject(y));
  383.     prnt_flush = prnt_flush || blocked(dest_index);
  384.     debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  385.     if( inners != nil )
  386.     { Promote(hd, NextDown(link), dest_index);
  387.       if( need_adjust )
  388.       { debug0(DSA, D, "  calling AdjustSize from FlushGalley (ACCEPT)");
  389.         AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  390.       }
  391.       FlushInners(inners, hd);
  392.       goto RESUME;
  393.     }
  394.     break;
  395.  
  396.  
  397.       default:
  398.       
  399.     Error(INTERN, &fpos(y), "FlushGalley: %s", Image(type(y)));
  400.     break;
  401.  
  402.     } /* end switch */
  403.  
  404.   } /* end for */
  405.  
  406.  
  407.   /* EMPTY: */
  408.  
  409.     /* galley is now completely accepted; clean up and exit */
  410.     debug0(DGF, DD, "  galley empty now");
  411.     if( inners != nil )  DisposeObject(inners);
  412.     if( Down(hd) != hd )
  413.     { Promote(hd, hd, dest_index);
  414.       if( need_adjust )
  415.       { debug0(DSA, D, "  calling AdjustSize from FlushGalley (EMPTY)");
  416.     AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  417.       }
  418.     }
  419.     DetachGalley(hd);
  420.     debug0(DGF, D, "  calling KillGalley from FlushGalley");
  421.     KillGalley(hd);
  422.     ParentFlush(dest_index, TRUE);
  423.     debug1(DGF,D,"] FlushGalley %s returning (emptied).", SymName(actual(hd)));
  424.       debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  425.     return;
  426.  
  427.  
  428.   REJECT:
  429.   
  430.     /* reject this component and move to a new dest */
  431.     debug1(DGF, D, "  reject %s", EchoObject(y));
  432.     assert(actual(dest) != PrintSym, "FlushGalley: reject print!");
  433.     if( inners != nil )  DisposeObject(inners);
  434.     if( stop_link != nil )
  435.     { Promote(hd, stop_link, dest_index);
  436.       if( need_adjust )
  437.       { debug0(DSA, D, "  calling AdjustSize from FlushGalley (REJECT)");
  438.     AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  439.       }
  440.     }
  441.     DetachGalley(hd);
  442.     assert( type(dest_index) == RECEIVING, "FlushGalley/REJECT: dest_index!" );
  443.     prnt_flush = prnt_flush || blocked(dest_index); /* **** bug fix **** */
  444.     DeleteNode(dest_index);
  445.     goto RESUME;
  446.  
  447.  
  448.   SUSPEND:
  449.   
  450.     /* suspend this component */
  451.     debug1(DGF, D, "  suspend %s", EchoObject(y));
  452.     if( inners != nil )  DisposeObject(inners);
  453.     if( stop_link != nil )
  454.     { Promote(hd, stop_link, dest_index);
  455.       if( need_adjust )
  456.       { debug0(DSA, D, "  calling AdjustSize from FlushGalley (SUSPEND)");
  457.     AdjustSize(dest_encl, dest_back, dest_fwd, ROW);
  458.       }
  459.     }
  460.  
  461.     /* check whether external galleys can remove the blockage */
  462.     if( type(y) == RECEPTIVE && ready_galls(hd) != nil && AllowCrossDb )
  463.     { OBJECT eg, val, index2, hd2, tag, seq, newsym;
  464.       BOOLEAN found, gall;  FULL_CHAR newtag[MAX_LINE], newseq[MAX_LINE];
  465.  
  466.       /* get first ready galley in from cross reference database */
  467.       Child(eg, Down(ready_galls(hd)));
  468.       val = ReadFromFile(eg_fnum(eg), eg_fpos(eg), nil);
  469.       if( val == nil ) Error(FATAL, &fpos(y),
  470.     "Error in database file %s", FileName(eg_fnum(eg)));
  471.       assert( type(val) == CLOSURE, "AttachG: db CLOSURE!" );
  472.       index2 = New(UNATTACHED);
  473.       hd2 = New(HEAD);
  474.       FposCopy(fpos(hd2), fpos(val));
  475.       actual(hd2) = actual(val);
  476.       backward(hd2) = TargetSymbol(val, &whereto(hd2));
  477.       backward(hd2) = sized(hd2) = FALSE;
  478.       ready_galls(hd2) = nil;
  479.       must_expand(hd2) = TRUE;
  480.       Link(index2, hd2);
  481.       Link(hd2, val);
  482.       Link(Up(y), index2);
  483.  
  484.       /* set up the next ready galley for reading next time */
  485.       Child(tag, Down(eg));  Child(seq, LastDown(eg));
  486.       do /* skip duplicate seq values */
  487.       {    found = DbRetrieveNext(OldCrossDb, &gall, &newsym,
  488.          newtag, newseq, &eg_fnum(eg), &eg_fpos(eg), &eg_cont(eg));
  489.     debug2(DGF, D, "  ext gall  found:   %15s  gall:    %15s",
  490.             bool(gall), bool(found));
  491.     debug2(DGF, D, "  ext gall  new sym: %15s  old sym: %15s",
  492.             SymName(newsym), SymName(eg_symbol(eg)));
  493.     debug2(DGF, D, "  ext gall  new tag: %15s  old tag: %15s",
  494.             newtag, string(tag));
  495.     debug2(DGF, D, "  ext gall  new seq: %15s  old seq: %15s",
  496.             newseq, string(seq));
  497.     if( found )  found = gall && newsym == eg_symbol(eg) &&
  498.             StringEqual(newtag, string(tag));
  499.       } while( found && StringEqual(newseq, string(seq)) );
  500.       if( found )
  501.       {    DisposeChild(Up(tag));
  502.     DisposeChild(Up(seq));
  503.     tag = MakeWord(WORD, newtag, no_fpos);
  504.     seq = MakeWord(WORD, newseq, no_fpos);
  505.     Link(eg, tag);  Link(eg, seq);
  506.     debug1(DGF,D, "  another ext gall: into %s", SymName(newsym));
  507.       }
  508.       else
  509.       {    DisposeChild(Up(eg));
  510.     debug1(DGF,D, "  last ext gall into ", SymName(eg_symbol(eg)));
  511.     if( Down(ready_galls(hd)) == ready_galls(hd) )
  512.     { Dispose(ready_galls(hd));
  513.       ready_galls(hd) = nil;
  514.       debug0(DGF,D, "  all ext galls exhausted");
  515.     }
  516.       }
  517.  
  518.       /* flush the ready galley found above, and resume */
  519.       debug2(DGF, D, "  ext gall FlushGalley (%s into %s)",
  520.             SymName(actual(hd2)), SymName(whereto(hd2)));
  521.       debug0(DGF, D, "  calling FlushGalley from FlushGalley/SUSPEND");
  522.       FlushGalley(hd2);
  523.       goto RESUME;
  524.     }
  525.     else if( type(y) == RECEPTIVE && trigger_externs(y) && AllowCrossDb )
  526.     { OBJECT sym, cr, ins, tag, seq, eg, cnt;  BOOLEAN found;
  527.       FULL_CHAR newseq[MAX_LINE];  FILE_NUM tfnum;  long tfpos, tcont;
  528.       debug1(DGF, D, "  ext gall target %s", SymName(actual(actual(y))));
  529.       for( sym = FirstExternTarget(actual(actual(y)), &cnt);
  530.          sym != nil;  sym = NextExternTarget(actual(actual(y)), &cnt) )
  531.       {
  532.     debug1(DGF, D, "  ext gall gall_targ %s", SymName(sym));
  533.     cr = GallTargEval(sym, &fpos(actual(y)));
  534.     ins = New(GALL_TARG);
  535.     actual(ins) = cr;
  536.     Link(Up(y), ins);
  537.     Child(tag, LastDown(cr));
  538.     assert( is_word(type(tag)), "FlushGalley: cr is_word(type(tag))!" );
  539.     found = DbRetrieve(OldCrossDb, TRUE, sym, string(tag),
  540.         newseq, &tfnum, &tfpos, &tcont);
  541.     if( found )
  542.     { if( ready_galls(hd) == nil )  ready_galls(hd) = New(ACAT);
  543.       eg = New(EXT_GALL);
  544.       debug1(DGF, D, "  ext gall retrieved: into %s", SymName(sym));
  545.       eg_fnum(eg) = tfnum;
  546.       eg_fpos(eg) = tfpos;
  547.       eg_symbol(eg) = sym;
  548.       eg_cont(eg) = tcont;
  549.       tag = MakeWord(WORD, string(tag), no_fpos);
  550.       Link(eg, tag);
  551.       seq = MakeWord(WORD, newseq, no_fpos);
  552.       Link(eg, seq);
  553.       Link(ready_galls(hd), eg);
  554.     }
  555.       }
  556.       trigger_externs(y) = FALSE;
  557.       if( ready_galls(hd) != nil )  goto RESUME;
  558.     } /* end if external galleys */
  559.  
  560.     /* if non-blocking, delete the index and resume */
  561.     if( type(y) == RECEPTIVE && non_blocking(y) )
  562.     { DeleteNode(y);
  563.       goto RESUME;
  564.     }
  565.     else if( type(y) == RECEIVING && non_blocking(y) )
  566.     {    
  567.       if( Down(y) == y )
  568.       {    DeleteNode(y);
  569.       }
  570.       else
  571.       {    Child(z, Down(y));
  572.     DetachGalley(z);
  573.       }
  574.       goto RESUME;
  575.     }
  576.  
  577.     /* if all the above fail to remove the blockage, suspend */
  578.     blocked(y) = TRUE;
  579.     ParentFlush(dest_index, FALSE);
  580.       debug1(DGF, D, "    prnt_flush = %s", bool(prnt_flush));
  581.     debug1(DGF, D, "] FlushGalley %s returning (suspend)", SymName(actual(hd)));
  582.     return;
  583.  
  584. } /* end FlushGalley */
  585.