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

  1. /*@z17.c:Gap Widths:GetGap()@*************************************************/
  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:         z17.c                                                      */
  26. /*  MODULE:       Gap Widths                                                 */
  27. /*  EXTERNS:      GetGap(), MinGap(), ExtraGap(), ActualGap(), EchoGap()     */
  28. /*                                                                           */
  29. /*****************************************************************************/
  30. #include "externs"
  31.  
  32.  
  33. /*****************************************************************************/
  34. /*                                                                           */
  35. /*  GetGap(x, style, res_gap, res_inc)                                       */
  36. /*                                                                           */
  37. /*  Object x is expected to be a WORD or QWORD containing a gap:             */
  38. /*                                                                           */
  39. /*      <gap>        ::=  [ <increment> ] <width> [ <mode> ]                 */
  40. /*                   ::=                                                     */
  41. /*      <width>      ::=  <unsigned number> <units>                          */
  42. /*      <units>      ::=  c  |  i  |  p  |  m  |  f  |  s                    */
  43. /*                   ::=  v  |  w  |  b  |  r  |  d                          */
  44. /*      <mode>       ::=  e  |  h  |  x  |  o  |  k  |  t                    */
  45. /*      <increment>  ::=  +  |  -                                            */
  46. /*                                                                           */
  47. /*  Set *res_gap to the gap in the strings of x; *res_inc is the increment.  */
  48. /*  The gap is calculated using the given style.                             */
  49. /*  If the gap is empty, this is a synonym for 0ie.                          */
  50. /*  If there is an error, GetGap prints a message and returns 0ie.           */
  51. /*                                                                           */
  52. /*****************************************************************************/
  53. #define setwidths(x, y) w = x; units(*res_gap) = y;  break;
  54.  
  55. GetGap(x, style, res_gap, res_inc)
  56. OBJECT x;  STYLE *style;  GAP *res_gap;  unsigned *res_inc;
  57. { int w;  float num; 
  58.   FULL_CHAR *str;
  59.  
  60.   debug2(DGW, D, "GetGap( %s, %s, res_gap, res_inc )",
  61.     EchoObject(x), EchoStyle(style));
  62.  
  63.   width(*res_gap) = 0;  units(*res_gap) = FIXED_UNIT;
  64.   mode(*res_gap)  = EDGE_MODE;  *res_inc = GAP_ABS;
  65.  
  66.   /* make sure we have a WORD or QWORD argument */
  67.   if( !is_word(type(x)) )
  68.   { Error(WARN, &fpos(x), "gap is not a simple word");
  69.     debug1(DGW, D, "GetGap failing (type(x) = %s)", Image(type(x)));
  70.     return;
  71.   }
  72.   str = string(x);
  73.  
  74.   /* if word is empty, return 0ie */
  75.   if( *str == '\0' )
  76.   { debug0(DGW, D, "GetGap returning (null word)");
  77.     return;
  78.   }
  79.  
  80.   /* find the gap increment */
  81.   if( *str == CH_INCGAP )       *res_inc = GAP_INC, str++;
  82.   else if( *str == CH_DECGAP )  *res_inc = GAP_DEC, str++;
  83.  
  84.   /* read the gap width */
  85.   if( sscanf((char *) str, "%f", &num) != 1 )
  86.   { Error(WARN, &fpos(x), "width missing from %s", string(x));
  87.     Error(WARN, &fpos(x), "reminder: /, | and & characters %s",
  88.         "must be enclosed in double quotes");
  89.     debug0(DGW, D, "GetGap failing (width missing)");
  90.     return;
  91.   }
  92.   while( numericchar(*str) )  str++;
  93.  
  94.   /* find the units, calculate length, and check for reasonableness */
  95.   switch( *str )
  96.   {
  97.     case CH_UNIT_CM:    setwidths( num*CM,                        FIXED_UNIT );
  98.     case CH_UNIT_IN:    setwidths( num*IN,                        FIXED_UNIT );
  99.     case CH_UNIT_PT:    setwidths( num*PT,                        FIXED_UNIT );
  100.     case CH_UNIT_EM:    setwidths( num*EM,                        FIXED_UNIT );
  101.     case CH_UNIT_FT:    setwidths( num*FontSize(font(*style), x), FIXED_UNIT );
  102.     case CH_UNIT_SP:    setwidths( num*width(space_gap(*style)),  FIXED_UNIT );
  103.     case CH_UNIT_VS:    setwidths( num*width(line_gap(*style)),   FIXED_UNIT );
  104.     case CH_UNIT_WD:    setwidths( num*FR,                        NEXT_UNIT  );
  105.     case CH_UNIT_BD:    setwidths( num*FR,                        FRAME_UNIT );
  106.     case CH_UNIT_RL:    setwidths( num*FR,                        AVAIL_UNIT );
  107.  
  108.     case CH_UNIT_DG:    if( *res_inc == GAP_DEC ) num = - num;
  109.             *res_inc = GAP_ABS;
  110.             while( num >= 360.0 ) num -= 360.0;
  111.             while( num <= -360.0 ) num += 360.0;
  112.             assert( (num>= -360) && (num<=360), "GetGap: dg!" );
  113.             setwidths( num*DG,                        DEG_UNIT   );
  114.  
  115.     default:    Error(WARN, &fpos(x), "units letter missing from %s",string(x));
  116.         debug0(DGW, D, "GetGap failing (units letter missing)");
  117.         return;
  118.   }
  119.  
  120.   if( units(*res_gap) == AVAIL_UNIT && w > FR )
  121.   { Error(WARN, &fpos(x), "%.1fr too large; replaced with 1.0r", num);
  122.     w = FR;
  123.   }
  124.   else if( w > MAX_LEN )
  125.   { assert( units(*res_gap) != DEG_UNIT, "GetGap: oversize degrees!" );
  126.     Error(WARN, &fpos(x), "length %s is too large - max (%dc) substituted",
  127.         string(x), MAX_LEN/CM);
  128.     w = MAX_LEN;
  129.   }
  130.   width(*res_gap) = w;
  131.  
  132.   /* find the gap mode */
  133.   switch( *++str )
  134.   {
  135.     case CH_MODE_EDGE:
  136.     case '\0':        mode(*res_gap) = EDGE_MODE;    break;
  137.     case CH_MODE_HYPH:    mode(*res_gap) = HYPH_MODE;    break;
  138.     case CH_MODE_MARK:    mode(*res_gap) = MARK_MODE;    break;
  139.     case CH_MODE_OVER:    mode(*res_gap) = OVER_MODE;    break;
  140.     case CH_MODE_KERN:    mode(*res_gap) = KERN_MODE;    break;
  141.     case CH_MODE_TABL:    mode(*res_gap) = TAB_MODE;    break;
  142.  
  143.     default:    Error(WARN, &fpos(x), "unknown gap mode in %s",string(x));
  144.         debug0(DGW, D, "GetGap failing (spacing mode)");
  145.         return;
  146.   }
  147.  
  148.   if( *str != '\0' && *++str != '\0' )
  149.     Error(WARN, &fpos(x), "invalid width or gap %s", string(x));
  150.  
  151.   debug2(DGW, D, "GetGap returning (res_gap = %s, res_inc = %s)",
  152.     EchoGap(res_gap), Image( (int) *res_inc) );
  153. } /* end GetGap */
  154.  
  155.  
  156. /*@::MinGap()@****************************************************************/
  157. /*                                                                           */
  158. /*  LENGTH MinGap(a, b, c, xgap)                                             */
  159. /*                                                                           */
  160. /*  Returns the minimum possible separation between the marks of two         */
  161. /*  objects with the given intervening gap.                                  */
  162. /*  The first object has fwd value a, the second has back value b and fwd c. */
  163. /*                                                                           */
  164. /*****************************************************************************/
  165.  
  166. LENGTH MinGap(a, b, c, xgap)
  167. LENGTH a, b, c;  GAP *xgap;
  168. { LENGTH res;  int w;
  169.   switch( units(*xgap) )
  170.   {
  171.     case FIXED_UNIT:    w = width(*xgap);
  172.             break;
  173.  
  174.     case FRAME_UNIT:    w = 0;
  175.             break;
  176.  
  177.     case AVAIL_UNIT:    w = 0;
  178.             break;
  179.  
  180.     case NEXT_UNIT:    w = width(*xgap) * (b + c) / FR;
  181.             break;
  182.  
  183.     default:        Error(INTERN, no_fpos, "MinGap: units = %d",
  184.                 units(*xgap));
  185.             break;
  186.   }
  187.   switch( mode(*xgap) )
  188.   {
  189.     case NO_MODE:    Error(INTERN, no_fpos, "MinGap: NO_MODE");
  190.             res = 0;
  191.             break;
  192.  
  193.     case ADD_HYPH:
  194.     case HYPH_MODE:
  195.     case EDGE_MODE:    res = min(MAX_LEN, a + w + b);
  196.             break;
  197.  
  198.     case MARK_MODE:    res = max(w, a + b);
  199.             break;
  200.  
  201.     case OVER_MODE:    res = w;
  202.             break;
  203.  
  204.     case KERN_MODE:    res = max(max(a, b), w);
  205.             break;
  206.  
  207.     case TAB_MODE:    res = a + b;
  208.             break;
  209.  
  210.     default:        Error(INTERN, no_fpos, "MinGap: %d", mode(*xgap));
  211.             res = 0;
  212.             break;
  213.  
  214.   }
  215.   debug5(DGW, D, "MinGap( _,%s  %s  %s,%s ) = %s", EchoLength(a),
  216.     EchoGap(xgap), EchoLength(b), EchoLength(c), EchoLength(res) );
  217.   return res;
  218. } /* end MinGap */
  219.  
  220.  
  221. /*@::ExtraGap()@**************************************************************/
  222. /*                                                                           */
  223. /*  LENGTH ExtraGap(a, b, xgap, dir)                                         */
  224. /*                                                                           */
  225. /*  Consider two objects, the first with forward length a, the second with   */
  226. /*  back length b.  The objects are separated by the given gap.              */
  227. /*  If dir == FWD, ExtraGap returns the maximum amount that a could be       */
  228. /*  increased without increasing MinGap(a, b, c, xgap).                      */
  229. /*  If dir == BACK, similarly for b.                                         */
  230. /*                                                                           */
  231. /*****************************************************************************/
  232.  
  233. LENGTH ExtraGap(a, b, xgap, dir)
  234. LENGTH a, b; GAP *xgap;  int dir;
  235. { LENGTH tmp, res;
  236.   LENGTH w = units(*xgap) == FIXED_UNIT ? width(*xgap) : 0;
  237.   switch( mode(*xgap) )
  238.   {
  239.     case NO_MODE:    Error(INTERN, no_fpos, "ExtraGap: NO_MODE");
  240.             res = 0;
  241.             break;
  242.  
  243.     case ADD_HYPH:
  244.     case HYPH_MODE:
  245.     case EDGE_MODE:    res = 0;
  246.             break;
  247.  
  248.     case MARK_MODE:    res = max(0, w - a - b);
  249.             break;
  250.  
  251.     case OVER_MODE:    res = MAX_LEN;
  252.             break;
  253.  
  254.     case KERN_MODE:    tmp = max(a, max(b, w));
  255.             res = dir == BACK ? tmp - b : tmp - a;
  256.             break;
  257.  
  258.     case TAB_MODE:    res = 0;
  259.             break;
  260.  
  261.     default:        Error(INTERN, no_fpos, "ExtraGap: %d", mode(*xgap));
  262.             res = 0;
  263.             break;
  264.  
  265.   }
  266.   debug5(DGW, DD, "ExtraGap( %s, %s, %s, %s ) = %s", EchoLength(a),
  267.         EchoLength(b), EchoGap(xgap), Image(dir), EchoLength(res));
  268.   return res;
  269. } /* end ExtraGap */
  270.  
  271.  
  272. /*@::ActualGap()@*************************************************************/
  273. /*                                                                           */
  274. /*  LENGTH ActualGap(a, b, c, xgap, f, mk)                                   */
  275. /*                                                                           */
  276. /*  Returns the actual separation between the marks of an object of size     */
  277. /*  (?, a) and an object of size (b, c) separated by gap *xgap in a frame    */
  278. /*  of size f; the first object lies at mk in the frame (0 <= mk <= f).      */
  279. /*                                                                           */
  280. /*****************************************************************************/
  281.  
  282. LENGTH ActualGap(a, b, c, xgap, f, mk)
  283. LENGTH a, b, c;  GAP *xgap;  LENGTH f, mk;
  284. { LENGTH res;  int w, w2;
  285.   switch( units(*xgap) )
  286.   {
  287.     case FIXED_UNIT:    w = width(*xgap);
  288.             break;
  289.  
  290.     case FRAME_UNIT:    w = (width(*xgap) * f) / FR;
  291.             break;
  292.  
  293.     case AVAIL_UNIT:    w = (width(*xgap) * (f - b - c)) / FR;
  294.             w = max(w, 0);
  295.             break;
  296.  
  297.     case NEXT_UNIT:    w = width(*xgap) * (b + c) / FR;
  298.             break;
  299.  
  300.     default:        Error(INTERN, no_fpos, "ActualGap: units = %d",
  301.                 units(*xgap));
  302.             break;
  303.   }
  304.   switch( mode(*xgap) )
  305.   {
  306.     case NO_MODE:    Error(INTERN, no_fpos, "ActualGap: NO_MODE");
  307.             w2 = 0;
  308.             break;
  309.  
  310.     case ADD_HYPH:
  311.     case HYPH_MODE:
  312.     case EDGE_MODE:    w2 = a + w + b;
  313.             break;
  314.  
  315.     case MARK_MODE:    w2 = max( w, a + b );
  316.             break;
  317.  
  318.     case OVER_MODE:    w2 = w;
  319.             break;
  320.  
  321.     case KERN_MODE:    w2 = max( max(a, b), w);
  322.             break;
  323.  
  324.     case TAB_MODE:    w2 = w + b - mk;
  325.             w2 = max( w2, a + b );
  326.             break;
  327.  
  328.     default:        Error(INTERN,no_fpos,"ActualGap: mode %d", mode(*xgap));
  329.             w2 = 0;
  330.             break;
  331.   }
  332.   res = min(MAX_LEN, w2);
  333.   debug6(DGW, D, "ActualGap( _,%s %s %s,%s; %s ) = %s",
  334.     EchoLength(a), EchoGap(xgap), EchoLength(b),
  335.     EchoLength(c), EchoLength(f), EchoLength(res) );
  336.   return res;
  337. } /* end ActualGap */
  338.  
  339.  
  340. /*@::EchoGap()@***************************************************************/
  341. /*                                                                           */
  342. /*  FULL_CHAR *EchoGap(xgap)                                                 */
  343. /*                                                                           */
  344. /*  Returns a static string showing the indicated xgap.                      */
  345. /*                                                                           */
  346. /*****************************************************************************/
  347. #if DEBUG_ON
  348.  
  349. FULL_CHAR *EchoGap(xgap)
  350. GAP *xgap;
  351. { char *letter = "?ehxokt";  char c;
  352.   static char buff[20];
  353.   assert( mode(*xgap) <= 6, "EchoGap: mode(*xgap)" );
  354.   c = letter[mode(*xgap)];
  355.   switch( units(*xgap) )
  356.   {
  357.     case 0:        sprintf(buff, "(none)%c", c);
  358.             break;
  359.  
  360.     case FIXED_UNIT:    sprintf(buff, "%.1fc%c", (float) width(*xgap) / CM, c);
  361.             break;
  362.  
  363.     case NEXT_UNIT:    sprintf(buff, "%.1fw%c", (float) width(*xgap) / FR, c);
  364.             break;
  365.  
  366.     case FRAME_UNIT:    sprintf(buff, "%.1fb%c", (float) width(*xgap) / FR, c);
  367.             break;
  368.  
  369.     case AVAIL_UNIT:    sprintf(buff, "%.1fr%c", (float) width(*xgap) / FR, c);
  370.             break;
  371.  
  372.     case DEG_UNIT:    sprintf(buff, "%.1fd", (float) width(*xgap) / DG);
  373.             break;
  374.  
  375.     default:        Error(INTERN, no_fpos, "EchoGap: %d", units(*xgap));
  376.             break;
  377.  
  378.   }
  379.   return AsciiToFull(buff);
  380. } /* end EchoGap */
  381. #endif
  382.