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

  1. /*@z12.c:Size Finder:MinSize()@***********************************************/
  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:         z12.c                                                      */
  26. /*  MODULE:       Size Finder                                                */
  27. /*  EXTERNS:      MinSize()                                                  */
  28. /*                                                                           */
  29. /*****************************************************************************/
  30. #include "externs"
  31. #define IG_LOOKING    0
  32. #define IG_NOFILE    1
  33. #define IG_BADFILE    2
  34. #define IG_BADSIZE    3
  35. #define    IG_OK        4
  36.  
  37.  
  38. /*****************************************************************************/
  39. /*                                                                           */
  40. /*  OBJECT MinSize(x, dim, extras)                                           */
  41. /*                                                                           */
  42. /*  Set fwd(x, dim) and back(x, dim) to their minimum possible values.       */
  43. /*  If dim == ROW, construct an extras list and return it in *extras.        */
  44. /*                                                                           */
  45. /*****************************************************************************/
  46.  
  47. OBJECT MinSize(x, dim, extras)
  48. OBJECT x;  int dim;  OBJECT *extras;
  49. { OBJECT y, z, link, prev, t, g, full_name;
  50.   int b, f, dble_fwd, llx, lly, urx, ury, status;
  51.   float fllx, flly, furx, fury;
  52.   BOOLEAN dble_found, found, will_expand, first_line;
  53.   FILE *fp;  FULL_CHAR buff[MAX_LINE];
  54.  
  55.   debug2(DSF, DD, "[ MinSize( %s, %s, extras )", EchoObject(x), dimen(dim));
  56.   ifdebug(DSF, DDD, DebugObject(x));
  57.  
  58.   switch( type(x) )
  59.   {
  60.  
  61.     case WORD:
  62.     case QWORD:
  63.     
  64.       if( dim == COL )  FontWordSize(x);
  65.       break;
  66.  
  67.  
  68.     case CROSS:
  69.  
  70.       /* add index to the cross-ref */
  71.       if( dim == ROW )
  72.       {    z = New(cross_type(x));
  73.     actual(z) = x;
  74.     Link(*extras, z);
  75.     debug1(DCR, DDD, "  MinSize: %s", EchoObject(z));
  76.       }
  77.       back(x, dim) = fwd(x, dim) = 0;
  78.       break;
  79.  
  80.  
  81.     case NULL_CLOS:
  82.     
  83.       back(x, dim) = fwd(x, dim) = 0;
  84.       break;
  85.  
  86.  
  87.     case HEAD:
  88.  
  89.       if( dim == ROW )
  90.       {    
  91.     /* replace the galley x by a dummy closure y */
  92.     y = New(NULL_CLOS);
  93.     FposCopy(fpos(y), fpos(x));
  94.     ReplaceNode(y, x);
  95.  
  96.     if( has_key(actual(x)) )
  97.     {
  98.       /* galley is sorted, make insinuated cross-reference */
  99.       z = backward(x) ? New(GALL_PREC) : New(GALL_FOLL);
  100.       Child(t, Down(x));
  101.       actual(z) = CrossMake(whereto(x), t, (int) type(z));
  102.       Link(*extras, z);
  103.       DisposeObject(x);
  104.       debug1(DCR, DDD, "  MinSize: %s", EchoObject(z));
  105.     }
  106.     else
  107.     {
  108.       /* galley is following, make UNATTACHED */
  109.       z = New(UNATTACHED);  Link(z, x);
  110.       Link(*extras, z);
  111.       debug1(DCR, DDD, "  MinSize: %s", EchoObject(z));
  112.     }
  113.     x = y;    /* now sizing y, not x */
  114.       }
  115.       else external(x) = FALSE;
  116.       back(x, dim) = fwd(x, dim) = 0;
  117.       break;
  118.  
  119.  
  120.     case CLOSURE:
  121.  
  122.       assert( !has_target(actual(x)), "MinSize: CLOSURE has target!" );
  123.       if( dim == ROW )
  124.       { if( indefinite(actual(x)) )
  125.     { z = New(RECEPTIVE);
  126.       actual(z) = x;
  127.       Link(*extras, z);
  128.       debug1(DCR, DDD, "  MinSize: %s", EchoObject(z));
  129.     }
  130.     else if( recursive(actual(x)) )
  131.     { z = New(RECURSIVE);
  132.       actual(z) = x;
  133.       Link(*extras, z);
  134.       debug1(DCR, DDD, "  MinSize: %s", EchoObject(z));
  135.     }
  136.     else Error(INTERN,&fpos(x), "MinSize: definite non-recursive CLOSURE!");
  137.       }
  138.       else external(x) = FALSE;        /*  nb must be done just here! */
  139.       back(x, dim) = fwd(x, dim) = 0;
  140.       break;
  141.  
  142.  
  143.     case ONE_COL:
  144.     case ONE_ROW:
  145.     case PADJUST:
  146.     case HADJUST:
  147.     case VADJUST:
  148.     case HCONTRACT:
  149.     case VCONTRACT:
  150.     
  151.       Child(y, Down(x));
  152.       y = MinSize(y, dim, extras);
  153.       back(x, dim) = back(y, dim);
  154.       fwd(x, dim)  = fwd(y, dim);
  155.       break;
  156.  
  157.  
  158.     case HEXPAND:
  159.     case VEXPAND:
  160.  
  161.       Child(y, Down(x));
  162.       y = MinSize(y, dim, extras);
  163.       back(x, dim) = back(y, dim);
  164.       fwd(x, dim)  = fwd(y, dim);
  165.  
  166.       /* insert index into *extras for expanding later */
  167.       if( dim == ROW )
  168.       {    z = New(EXPAND_IND);
  169.     actual(z) = x;
  170.     Link(*extras, z);
  171.     debug1(DCR, DDD, "  MinSize: %s", EchoObject(z));
  172.       }    
  173.       break;
  174.  
  175.  
  176.     case GRAPHIC:
  177.     
  178.       Child(y, LastDown(x));
  179.       y = MinSize(y, dim, extras);
  180.       back(x, dim) = back(y, dim);
  181.       fwd(x, dim)  = fwd(y, dim);
  182.       break;
  183.  
  184.  
  185.     case HSCALE:
  186.     case VSCALE:
  187.  
  188.       /* work out size and set to 0 if parallel */
  189.       Child(y, Down(x));
  190.       y = MinSize(y, dim, extras);
  191.       if( (dim == COL) == (type(x) == HSCALE) )
  192.     back(x, dim) = fwd(x, dim) = 0;
  193.       else
  194.       {    back(x, dim) = back(y, dim);
  195.     fwd(x, dim)  = fwd(y, dim);
  196.       }
  197.       break;
  198.  
  199.  
  200.     case ROTATE:
  201.     
  202.       Child(y, Down(x));
  203.       if( dim == COL )
  204.       {    y = MinSize(y, COL, extras);
  205.     whereto(x) = New(ACAT);
  206.     y = MinSize(y, ROW, &whereto(x));
  207.     RotateSize(&back(x, COL), &fwd(x, COL), &back(x, ROW), &fwd(x, ROW),
  208.       y, sparec(constraint(x)));
  209.       }
  210.       else
  211.       {    TransferLinks(Down(whereto(x)), whereto(x), *extras);
  212.     Dispose(whereto(x));
  213.       }
  214.       break;
  215.     
  216.  
  217.     case SCALE:
  218.  
  219.       Child(y, Down(x));
  220.       y = MinSize(y, dim, extras);
  221.       if( dim == COL )
  222.       { back(x, dim) = (back(y, dim) * bc(constraint(x))) / SF;
  223.         fwd(x, dim)  = (fwd(y, dim)  * bc(constraint(x))) / SF;
  224.       }
  225.       else
  226.       { back(x, dim) = (back(y, dim) * fc(constraint(x))) / SF;
  227.         fwd(x, dim)  = (fwd(y, dim)  * fc(constraint(x))) / SF;
  228.       }
  229.       break;
  230.  
  231.  
  232.     case WIDE:
  233.  
  234.       Child(y, Down(x));
  235.       y = MinSize(y, dim, extras);
  236.       if( dim == COL )
  237.       { y = BreakObject(y, &constraint(x));
  238.         assert( FitsConstraint(back(y, dim), fwd(y, dim), constraint(x)),
  239.         "MinSize: BreakObject failed to fit!" );
  240.         back(x, dim) = back(y, dim);
  241.     fwd(x, dim)  = fwd(y, dim);
  242.     EnlargeToConstraint(&back(x, dim), &fwd(x, dim), &constraint(x));
  243.       }
  244.       else
  245.       {    back(x, dim) = back(y, dim);
  246.     fwd(x, dim)  = fwd(y, dim);
  247.       }
  248.       break;
  249.  
  250.  
  251.     case HIGH:
  252.     
  253.       Child(y, Down(x));
  254.       y = MinSize(y, dim, extras);
  255.       if( dim == ROW )
  256.       { if( !FitsConstraint(back(y, dim), fwd(y, dim), constraint(x)) )
  257.         { Error(WARN, &fpos(x), "forced to enlarge %s", KW_HIGH);
  258.       debug0(DSF, D, "offending object was:");
  259.       ifdebug(DSF, D, DebugObject(y));
  260.       SetConstraint(constraint(x), MAX_LEN, size(y, dim), MAX_LEN);
  261.         }
  262.         back(x, dim) = back(y, dim);
  263.     fwd(x, dim)  = fwd(y, dim);
  264.     EnlargeToConstraint(&back(x, dim), &fwd(x, dim), &constraint(x));
  265.       }
  266.       else
  267.       {    back(x, dim) = back(y, dim);
  268.     fwd(x, dim)  = fwd(y, dim);
  269.       }
  270.       break;
  271.  
  272.  
  273.     case SPLIT:
  274.     
  275.       link = DownDim(x, dim);  Child(y, link);
  276.       y = MinSize(y, dim, extras);
  277.       back(x, dim) = back(y, dim);
  278.       fwd(x, dim)  = fwd(y, dim);
  279.       break;
  280.  
  281.  
  282.     case ACAT:
  283.     case HCAT:
  284.     case VCAT:
  285.     
  286.       if( (dim == ROW) == (type(x) == VCAT) )
  287.       {
  288.     /********************************************************************/
  289.     /*                                                                  */
  290.     /*  Calculate sizes parallel to join direction; loop invariant is:  */
  291.     /*                                                                  */
  292.     /*     If prev == nil, there are no definite children equal to or   */
  293.     /*        to the left of Child(link).                               */
  294.     /*     If prev != nil, prev is the rightmost definite child to the  */
  295.     /*        left of Child(link), and (b, f) is the total size up to   */
  296.     /*        the mark of prev i.e. not including fwd(prev).            */
  297.     /*     g is the most recent gap, or nil if none found yet.          */
  298.     /*     will_expand == TRUE when a gap is found that is likely to    */
  299.     /*        enlarge when ActualGap is called later on.                */
  300.     /*                                                                  */
  301.     /********************************************************************/
  302.  
  303.     prev = g = nil;  will_expand = FALSE;  must_expand(x) = FALSE;
  304.     for( link = Down(x);  link != x;  link = NextDown(link) )
  305.     { Child(y, link);
  306.       if( is_index(type(y)) )
  307.       { if( dim == ROW )
  308.         { link = PrevDown(link);
  309.           MoveLink(NextDown(link), *extras, PARENT);
  310.         }
  311.         continue;
  312.       }
  313.       else if( type(y) == type(x) )
  314.       { link = PrevDown(link);
  315.         TransferLinks(Down(y), y, NextDown(link));
  316.         DisposeChild(Up(y));
  317.         continue;
  318.       }
  319.       else if( type(y) == GAP_OBJ )  g = y;
  320.       else /* calculate size of y and accumulate it */
  321.       { if( is_word(type(y)) )
  322.         { if( dim == COL )
  323.           {    FontWordSize(y);
  324.         debug4(DSF, DD, "FontWordSize( %s ) font %d = %s,%s",
  325.         EchoObject(y), word_font(y),
  326.         EchoLength(back(y, COL)), EchoLength(fwd(y, COL)));
  327.           }
  328.         }
  329.         else y = MinSize(y, dim, extras);
  330.  
  331.         if( is_indefinite(type(y)) )
  332.         {
  333.           /* error if preceding gap has mark */
  334.           if( g != nil && mark(gap(g)) )
  335.           {    Error(WARN, &fpos(y), "catenation modifier ^ deleted (%s)",
  336.             "it may not precede this object");
  337.         mark(gap(g)) = FALSE;
  338.           }
  339.  
  340.           /* error if next unit is used in preceding gap */
  341.           if( g != nil && units(gap(g)) == NEXT_UNIT )
  342.           {    Error(WARN, &fpos(y), "gap replaced by 0i (%s)",
  343.             "unit n may not precede this object");
  344.         units(gap(g)) = FIXED_UNIT;
  345.         width(gap(g)) = 0;
  346.           }
  347.         }
  348.         else
  349.         {
  350.           /* calculate running total length */
  351.           if( prev == nil )  b = back(y, dim), f = 0;
  352.           else
  353.           {
  354.         assert( g!=nil && mode(gap(g))!=NO_MODE, "MinSize: NO_MODE!" );
  355.         f += MinGap(fwd(prev, dim), back(y, dim), fwd(y, dim), &gap(g));
  356.         if( units(gap(g)) == FRAME_UNIT && width(gap(g)) > FR )
  357.             will_expand = TRUE;
  358.         if( mark(gap(g)) )  b += f, f = 0;
  359.           }
  360.           prev = y;
  361.         }
  362.         debug2(DSF,DD,"  b = %s, f = %s",EchoLength(b),EchoLength(f));
  363.       }
  364.     } /* end for */
  365.  
  366.     if( prev == nil )  b = f = 0;
  367.     else f += fwd(prev, dim);
  368.     back(x, dim) = min(MAX_LEN, b);
  369.     fwd(x, dim)  = min(MAX_LEN, f);
  370.  
  371.     if( type(x) == ACAT && will_expand )  fwd(x, COL) = MAX_LEN;
  372.       }
  373.       else
  374.       {
  375.     /********************************************************************/
  376.     /*                                                                  */
  377.     /*  Calculate sizes perpendicular to join direction                 */
  378.     /*                                                                  */
  379.     /*  Loop invariant:                                                 */
  380.     /*                                                                  */
  381.     /*     if found, (b, f) is the size of x, from the last // or from  */
  382.     /*     the start, up to link exclusive.  Else no children yet.      */
  383.     /*     If dble_found, a previous // exists, and (0, dble_fwd) is    */
  384.     /*     the size of x from the start up to that //.                  */
  385.     /*                                                                  */
  386.     /********************************************************************/
  387.  
  388.     dble_found = found = FALSE;  dble_fwd = 0;
  389.     for( link = Down(x);  link != x;  link = NextDown(link) )
  390.     { Child(y, link);
  391.       if( is_index(type(y)) )
  392.       { if( dim == ROW )
  393.         { link = PrevDown(link);
  394.           MoveLink(NextDown(link), *extras, PARENT);
  395.         }
  396.         continue;
  397.       }
  398.       else if( type(y) == type(x) )
  399.       { link = PrevDown(link);
  400.         TransferLinks(Down(y), y, NextDown(link));
  401.         DisposeChild(Up(y));
  402.         continue;
  403.       }
  404.       else if( type(y) == GAP_OBJ )
  405.       { assert( found, "MinSize/VCAT/perp: !found!" );
  406.         if( !join(gap(y)) )
  407.         {
  408.           /* found // or || operator, so end current group */
  409.           dble_found = TRUE;
  410.           dble_fwd = max(dble_fwd, b + f);
  411.           debug1(DSF, DD, "  endgroup, dble_fwd: %s", EchoLength(dble_fwd));
  412.           found = FALSE;
  413.         }
  414.       }
  415.       else /* found object */
  416.       {
  417.         /* calculate size of subobject y */
  418.         if( is_word(type(y)) )
  419.         { if( dim == COL )  FontWordSize(y);
  420.         }
  421.         else y = MinSize(y, dim, extras);
  422.         if( found )
  423.         { b = max(b, back(y, dim));
  424.           f = max(f, fwd(y, dim));
  425.         }
  426.         else
  427.         { b = back(y, dim);
  428.           f = fwd(y, dim);
  429.           found = TRUE;
  430.         }
  431.         debug2(DSF,DD, "  b: %s, f: %s", EchoLength(b), EchoLength(f));
  432.       }
  433.     } /* end for */
  434.     assert( found, "MinSize/VCAT/perp: !found (2)!" );
  435.  
  436.     /* finish off last group */
  437.     if( dble_found )
  438.     { back(x, dim) = 0;
  439.       dble_fwd = max(dble_fwd, b + f);
  440.       fwd(x, dim) = min(MAX_LEN, dble_fwd);
  441.       debug1(DSF, DD, "  end group, dble_fwd: %s", EchoLength(dble_fwd));
  442.     }
  443.     else
  444.     { back(x, dim) = b;
  445.       fwd(x, dim)  = f;
  446.     }
  447.       } /* end else */
  448.       break;
  449.  
  450.  
  451.     case COL_THR:
  452.     case ROW_THR:
  453.  
  454.       assert( (type(x) == COL_THR) == (dim == COL), "Manifest/COL_THR: dim!" );
  455.       if( thr_state(x) == NOTSIZED )
  456.       {    assert( Down(x) != x, "Manifest/COL_THR: Down(x)!" );
  457.     Child(y, Down(x));
  458.     y = MinSize(y, dim, extras);
  459.     b = back(y, dim);
  460.     f = fwd(y, dim);
  461.     for( link = NextDown(Down(x));  link != x;  link = NextDown(link) )
  462.     { Child(y, link);
  463.       assert( type(y) != GAP_OBJ, "Manifest/COL_THR: GAP_OBJ!" );
  464.       y = MinSize(y, dim, extras);
  465.       b = max(b, back(y, dim));
  466.       f = max(f, fwd(y, dim));
  467.     }
  468.     back(x, dim) = b;
  469.     fwd(x, dim)  = f;
  470.     thr_state(x) = SIZED;
  471.       }
  472.       break;
  473.  
  474.  
  475.     case INCGRAPHIC:
  476.     case SINCGRAPHIC:
  477.  
  478.       /* open file, check for initial %!, and hunt for %%BoundingBox line */
  479.       /* according to DSC Version 3.0, the BoundingBox parameters must be */
  480.       /* integers; but we read them as floats and truncate since files    */
  481.       /* with fractional values seem to be common in the real world       */
  482.       if( dim == ROW )  break;
  483.       status = IG_LOOKING;
  484.       Child(y, Down(x));
  485.       fp = OpenIncGraphicFile(string(y), type(x), &full_name, &fpos(y));
  486.       /* *** fp = OpenFile(fnum = sparec(constraint(x)), FALSE); */
  487.       if( fp == NULL )  status = IG_NOFILE;
  488.       first_line = TRUE;
  489.       while( status == IG_LOOKING && StringFGets(buff, MAX_LINE, fp) != NULL )
  490.       {
  491.     if( first_line && !StringBeginsWith(buff, AsciiToFull("%!")) )
  492.       status = IG_BADFILE;
  493.     else
  494.     { first_line = FALSE;
  495.       if( buff[0] == '%'
  496.           && StringBeginsWith(buff, AsciiToFull("%%BoundingBox:"))
  497.           && !StringContains(buff, AsciiToFull("(atend)")) )
  498.       { if( sscanf( (char *) buff, "%%%%BoundingBox: %f %f %f %f",
  499.         &fllx, &flly, &furx, &fury) == 4 )
  500.         {
  501.           status = IG_OK;
  502.           llx = fllx;
  503.           lly = flly;
  504.           urx = furx;
  505.           ury = fury;
  506.         }
  507.         else status = IG_BADSIZE;
  508.       }
  509.     }
  510.       }
  511.  
  512.       /* report error or calculate true size, depending on status */
  513.       switch( status )
  514.       {
  515.     case IG_LOOKING:
  516.  
  517.       Error(WARN, &fpos(x), "%s given zero size: format error in file %s%s",
  518.         type(x) == INCGRAPHIC ? KW_INCGRAPHIC : KW_SINCGRAPHIC,
  519.         string(full_name), " (missing %%BoundingBox: line)");
  520.       back(y, COL) = fwd(y, COL) = back(y, ROW) = fwd(y, ROW) = 0;
  521.       back(x, COL) = fwd(x, COL) = back(x, ROW) = fwd(x, ROW) = 0;
  522.       sparec(constraint(x)) = TRUE;
  523.       fclose(fp);
  524.       break;
  525.  
  526.     case IG_NOFILE:
  527.  
  528.       Error(WARN, &fpos(x), "%s deleted: cannot open file %s",
  529.         type(x) == INCGRAPHIC ? KW_INCGRAPHIC : KW_SINCGRAPHIC,
  530.         string(full_name));
  531.       sparec(constraint(x)) = FALSE;
  532.       back(x, COL) = fwd(x, COL) = back(x, ROW) = fwd(x, ROW) = 0;
  533.       break;
  534.  
  535.     case IG_BADFILE:
  536.  
  537.       Error(WARN, &fpos(x), "%s deleted: format error in file %s %s",
  538.         type(x) == INCGRAPHIC ? KW_INCGRAPHIC : KW_SINCGRAPHIC,
  539.         string(full_name), "(bad first line)");
  540.       sparec(constraint(x)) = FALSE;
  541.       back(x, COL) = fwd(x, COL) = back(x, ROW) = fwd(x, ROW) = 0;
  542.       fclose(fp);
  543.       break;
  544.     
  545.     case IG_BADSIZE:
  546.  
  547.       Error(WARN, &fpos(x), "%s given zero size: format error in file %s%s",
  548.         type(x) == INCGRAPHIC ? KW_INCGRAPHIC : KW_SINCGRAPHIC,
  549.         string(full_name), " (bad %%BoundingBox: line)");
  550.       back(y, COL) = fwd(y, COL) = back(y, ROW) = fwd(y, ROW) = 0;
  551.       back(x, COL) = fwd(x, COL) = back(x, ROW) = fwd(x, ROW) = 0;
  552.       sparec(constraint(x)) = TRUE;
  553.       fclose(fp);
  554.       break;
  555.  
  556.     case IG_OK:
  557.  
  558.       Child(y, Down(x));
  559.       back(y, COL) = llx;  fwd(y, COL) = urx;
  560.       back(y, ROW) = lly;  fwd(y, ROW) = ury;
  561.       b = (urx - llx) * PT;
  562.       b = max(0, min(b, MAX_LEN));
  563.       back(x, COL) = fwd(x, COL) = b / 2;
  564.       b = (ury - lly) * PT;
  565.       b = max(0, min(b, MAX_LEN));
  566.       back(x, ROW) = fwd(x, ROW) = b / 2;
  567.       sparec(constraint(x)) = TRUE;
  568.       fclose(fp);
  569.       break;
  570.  
  571.       }
  572.       DisposeObject(full_name);
  573.       break;
  574.  
  575.  
  576.     default:
  577.     
  578.       Error(INTERN, &fpos(x), "MinSize: type(x): %s", Image(type(x)));
  579.       break;
  580.  
  581.  
  582.   } /* end switch */
  583.   debug1(DSF, DD,  "] MinSize returning, x = %s", EchoObject(x));
  584.   debug3(DSF, DD, "  (%s size is %s, %s)", dimen(dim),
  585.         EchoLength(back(x, dim)), EchoLength(fwd(x, dim)) );
  586.   ifdebug(DSF, DDD, DebugObject(x));
  587.  
  588.   assert( back(x, dim) >= 0, "MinSize: back(x, dim) < 0!" );
  589.   assert( fwd(x, dim)  >= 0, "MinSize: fwd(x, dim)  < 0!" );
  590.  
  591.   return x;
  592. } /* end MinSize */
  593.