aboutsummaryrefslogtreecommitdiffstats
path: root/z17.c
diff options
context:
space:
mode:
Diffstat (limited to 'z17.c')
-rw-r--r--z17.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/z17.c b/z17.c
new file mode 100644
index 0000000..f57c92b
--- /dev/null
+++ b/z17.c
@@ -0,0 +1,407 @@
+/*@z17.c:Gap Widths:GetGap()@*************************************************/
+/* */
+/* 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: z17.c */
+/* MODULE: Gap Widths */
+/* EXTERNS: GetGap(), MinGap(), ExtraGap(), ActualGap(), EchoGap() */
+/* */
+/*****************************************************************************/
+#include "externs.h"
+
+
+/*****************************************************************************/
+/* */
+/* GetGap(x, style, res_gap, res_inc) */
+/* */
+/* Object x is expected to be a WORD or QWORD containing a gap: */
+/* */
+/* <gap> ::= [ <increment> ] <width> [ <mode> ] [ <nobreak> ] */
+/* ::= */
+/* */
+/* <nobreak> ::= u */
+/* <increment> ::= + | - */
+/* <width> ::= <unsigned number> <units> */
+/* <units> ::= c | i | p | m | f | s */
+/* ::= v | w | b | r | d | y | z */
+/* <mode> ::= e | h | x | o | k | t | n */
+/* */
+/* Set *res_gap to the gap in the strings of x; *res_inc is the increment. */
+/* The gap is calculated using the given style. */
+/* If the gap is empty, this is a synonym for 0ie. */
+/* If there is an error, GetGap prints a message and returns 0ie. */
+/* */
+/*****************************************************************************/
+#define setwidths(x, y) w = x; units(*res_gap) = y; break;
+
+void GetGap(OBJECT x, STYLE *style, GAP *res_gap, unsigned *res_inc)
+{ int w; float num;
+ FULL_CHAR *str;
+
+ debug2(DGW, DD, "GetGap( %s, %s, res_gap, res_inc )",
+ EchoObject(x), EchoStyle(style));
+
+ nobreak(*res_gap) = FALSE;
+ width(*res_gap) = 0; units(*res_gap) = FIXED_UNIT;
+ mode(*res_gap) = EDGE_MODE; *res_inc = GAP_ABS;
+
+ /* make sure we have a WORD or QWORD argument */
+ if( !is_word(type(x)) )
+ { Error(17, 1, "gap is not a simple word", WARN, &fpos(x));
+ debug1(DGW, DD, "GetGap failing (type(x) = %s)", Image(type(x)));
+ return;
+ }
+ str = string(x);
+
+ /* if word is empty, return 0ie */
+ if( *str == '\0' )
+ { debug0(DGW, DD, "GetGap returning (null word)");
+ return;
+ }
+
+ /* read the optional gap increment */
+ if( *str == CH_INCGAP ) *res_inc = GAP_INC, str++;
+ else if( *str == CH_DECGAP ) *res_inc = GAP_DEC, str++;
+
+ /* read the gap width */
+ if( sscanf((char *) str, "%f", &num) != 1 )
+ { Error(17, 2, "width missing from %s", WARN, &fpos(x), string(x));
+ Error(17, 3, "%s, %s and %s must be enclosed in double quotes",
+ WARN, &fpos(x), KW_VCAT_NJ, KW_HCAT_NJ, KW_ACAT_NJ);
+ debug0(DGW, DD, "GetGap failing (width missing)");
+ return;
+ }
+ while( numericchar(*str) ) str++;
+
+ /* read the compulsory units, calculate length, and check reasonableness */
+ switch( *str++ )
+ {
+ case CH_UNIT_CM: setwidths( num*CM, FIXED_UNIT );
+ case CH_UNIT_IN: setwidths( num*IN, FIXED_UNIT );
+ case CH_UNIT_PT: setwidths( num*PT, FIXED_UNIT );
+ case CH_UNIT_EM: setwidths( num*EM, FIXED_UNIT );
+ case CH_UNIT_FT: setwidths( num*FontSize(font(*style), x), FIXED_UNIT );
+ case CH_UNIT_SP: setwidths( num*width(space_gap(*style)), FIXED_UNIT );
+ case CH_UNIT_VS: setwidths( num*width(line_gap(*style)), FIXED_UNIT );
+ case CH_UNIT_YU: setwidths( num*yunit(*style), FIXED_UNIT );
+ case CH_UNIT_ZU: setwidths( num*zunit(*style), FIXED_UNIT );
+ case CH_UNIT_WD: setwidths( num*FR, NEXT_UNIT );
+ case CH_UNIT_BD: setwidths( num*FR, FRAME_UNIT );
+ case CH_UNIT_RL: setwidths( num*FR, AVAIL_UNIT );
+
+ case CH_UNIT_DG: if( *res_inc == GAP_DEC ) num = - num;
+ *res_inc = GAP_ABS;
+ while( num > 180.0 ) num -= 360.0;
+ while( num < -180.0 ) num += 360.0;
+ assert((num>=-180.0) && (num<=180.0), "GetGap: dg!");
+ setwidths( num*DG, DEG_UNIT );
+
+ default: Error(17, 4, "units letter missing from %s",
+ WARN, &fpos(x), string(x));
+ debug0(DGW, DD, "GetGap failing (units letter missing)");
+ return;
+ }
+
+ if( units(*res_gap) == AVAIL_UNIT && w > FR )
+ { Error(17, 5, "%.1fr too large (1.0r substituted)", WARN, &fpos(x), num);
+ w = FR;
+ }
+ width(*res_gap) = w;
+
+ /* read the optional gap mode */
+ switch( *str )
+ {
+ case CH_NOBREAK:
+ case '\0': mode(*res_gap) = EDGE_MODE; break;
+ case CH_MODE_EDGE: mode(*res_gap) = EDGE_MODE; str++; break;
+ case CH_MODE_HYPH: mode(*res_gap) = HYPH_MODE; str++; break;
+ case CH_MODE_MARK: mode(*res_gap) = MARK_MODE; str++; break;
+ case CH_MODE_OVER: mode(*res_gap) = OVER_MODE; str++; break;
+ case CH_MODE_KERN: mode(*res_gap) = KERN_MODE; str++; break;
+ case CH_MODE_TABL: mode(*res_gap) = TAB_MODE; str++; break;
+
+ default: Error(17, 7, "unknown gap mode in %s",
+ WARN, &fpos(x), string(x));
+ debug0(DGW, DD, "GetGap failing (spacing mode)");
+ return;
+ }
+
+ /* read the optional nobreak */
+ if( *str == CH_NOBREAK )
+ {
+ if( mode(*res_gap) == HYPH_MODE )
+ Error(17, 9, "replacing self-contradictory gap %s by breakable version",
+ WARN, &fpos(x), string(x));
+ else nobreak(*res_gap) = TRUE;
+ str++;
+ }
+
+ /* if string has not terminated, error */
+ if( *str != '\0' )
+ Error(17, 8, "invalid width or gap %s", WARN, &fpos(x), string(x));
+
+ debug2(DGW, DD, "GetGap returning (res_gap = %s, res_inc = %s)",
+ EchoGap(res_gap), Image( (int) *res_inc) );
+} /* end GetGap */
+
+
+/*@::MinGap()@****************************************************************/
+/* */
+/* FULL_LENGTH MinGap(a, b, c, xgap) */
+/* */
+/* Returns the minimum possible separation between the marks of two */
+/* objects with the given intervening gap. */
+/* The first object has fwd value a, the second has back value b and fwd c. */
+/* */
+/*****************************************************************************/
+
+FULL_LENGTH MinGap(FULL_LENGTH a, FULL_LENGTH b, FULL_LENGTH c, GAP *xgap)
+{ FULL_LENGTH res; int w;
+ switch( units(*xgap) )
+ {
+ case FIXED_UNIT: w = width(*xgap);
+ break;
+
+ case FRAME_UNIT: w = 0;
+ break;
+
+ case AVAIL_UNIT: w = 0;
+ break;
+
+ case NEXT_UNIT: w = width(*xgap) * (b + c) / FR;
+ break;
+
+ default: assert(FALSE, "MinGap: units");
+ break;
+ }
+ switch( mode(*xgap) )
+ {
+ case NO_MODE: assert(FALSE, "MinGap: NO_MODE");
+ res = 0;
+ break;
+
+ case ADD_HYPH:
+ case HYPH_MODE:
+ case EDGE_MODE: res = find_min(MAX_FULL_LENGTH, a + w + b);
+ break;
+
+ case MARK_MODE: if( BackEnd != PLAINTEXT )
+ res = find_max(w, a + b + (FULL_LENGTH) (0.1 * w) );
+ else
+ res = find_max(w, a + b);
+ break;
+
+ case OVER_MODE: res = w;
+ break;
+
+ case KERN_MODE: res = find_max(find_max(a, b), w);
+ break;
+
+ case TAB_MODE: res = a + b;
+ break;
+
+ default: assert(FALSE, "MinGap: mode");
+ res = 0;
+ break;
+
+ }
+ debug5(DGW, DD, "MinGap( _,%s %s %s,%s ) = %s", EchoLength(a),
+ EchoGap(xgap), EchoLength(b), EchoLength(c), EchoLength(res) );
+ return res;
+} /* end MinGap */
+
+
+/*@::ExtraGap()@**************************************************************/
+/* */
+/* FULL_LENGTH ExtraGap(a, b, xgap, dir) */
+/* */
+/* Consider two objects, the first with forward length a, the second with */
+/* back length b. The objects are separated by the given gap. */
+/* If dir == FWD, ExtraGap returns the maximum amount that a could be */
+/* increased without increasing MinGap(a, b, c, xgap). */
+/* If dir == BACK, similarly for b. */
+/* */
+/*****************************************************************************/
+
+FULL_LENGTH ExtraGap(FULL_LENGTH a, FULL_LENGTH b, GAP *xgap, int dir)
+{ FULL_LENGTH tmp, res;
+ FULL_LENGTH w = units(*xgap) == FIXED_UNIT ? width(*xgap) : 0;
+ switch( mode(*xgap) )
+ {
+ case NO_MODE: assert(FALSE, "ExtraGap: NO_MODE");
+ res = 0;
+ break;
+
+ case ADD_HYPH:
+ case HYPH_MODE:
+ case EDGE_MODE: res = 0;
+ break;
+
+ case MARK_MODE: if( BackEnd != PLAINTEXT )
+ res = find_max(0, (FULL_LENGTH) (0.9 * w) - a - b);
+ else
+ res = find_max(0, w - a - b);
+ break;
+
+ case OVER_MODE: res = MAX_FULL_LENGTH;
+ break;
+
+ case KERN_MODE: tmp = find_max(a, find_max(b, w));
+ res = dir == BACK ? tmp - b : tmp - a;
+ break;
+
+ case TAB_MODE: res = 0;
+ break;
+
+ default: assert(FALSE, "ExtraGap: mode");
+ res = 0;
+ break;
+
+ }
+ debug5(DGW, DD, "ExtraGap( %s, %s, %s, %s ) = %s", EchoLength(a),
+ EchoLength(b), EchoGap(xgap), Image(dir), EchoLength(res));
+ return res;
+} /* end ExtraGap */
+
+
+/*@::ActualGap()@*************************************************************/
+/* */
+/* FULL_LENGTH ActualGap(prevf, b, f, xgap, frame_size, mk) */
+/* */
+/* Returns the actual separation between the marks of an object of size */
+/* (?, prevf) and an object of size (b, f) separated by gap *xgap in a */
+/* frame of size frame_size; the first object lies at mk in the frame, */
+/* where 0 <= mk <= frame_size. */
+/* */
+/*****************************************************************************/
+
+FULL_LENGTH ActualGap(FULL_LENGTH prevf, FULL_LENGTH b, FULL_LENGTH f,
+ GAP *xgap, FULL_LENGTH frame_size, FULL_LENGTH mk)
+{ FULL_LENGTH res; int w, w2;
+ switch( units(*xgap) )
+ {
+ case FIXED_UNIT: w = width(*xgap);
+ break;
+
+ case FRAME_UNIT: if( width(*xgap) > FR )
+ w = MAX_FULL_LENGTH;
+ else
+ w = (width(*xgap) * frame_size) / FR;
+ break;
+
+ case AVAIL_UNIT: w = (width(*xgap) * (frame_size - b - f)) / FR;
+ w = find_max(w, 0);
+ break;
+
+ case NEXT_UNIT: w = width(*xgap) * (b + f) / FR;
+ break;
+
+ default: assert(FALSE, "ActualGap: units");
+ break;
+ }
+ switch( mode(*xgap) )
+ {
+ case NO_MODE: Error(17, 10, "cannot continue after previous error(s)", FATAL, no_fpos);
+ assert(FALSE, "ActualGap: NO_MODE");
+ w2 = 0;
+ break;
+
+ case ADD_HYPH:
+ case HYPH_MODE:
+ case EDGE_MODE: w2 = prevf + w + b;
+ break;
+
+ case MARK_MODE: if( BackEnd != PLAINTEXT )
+ w2 = find_max(w, prevf + b + (FULL_LENGTH) (0.1 * w) );
+ else
+ w2 = find_max(w, prevf + b);
+ break;
+
+ case OVER_MODE: w2 = w;
+ break;
+
+ case KERN_MODE: w2 = find_max( find_max(prevf, b), w);
+ break;
+
+ case TAB_MODE: w2 = w + b - mk;
+ w2 = find_max(w2, prevf + b );
+ break;
+
+ default: assert(FALSE, "ActualGap: mode");
+ w2 = 0;
+ break;
+ }
+ res = find_min(MAX_FULL_LENGTH, w2);
+ debug7(DGW, D, "ActualGap( _,%s %s %s,%s; frame_size %s, mk %s ) = %s",
+ EchoLength(prevf), EchoGap(xgap), EchoLength(b), EchoLength(f),
+ EchoLength(frame_size), EchoLength(mk), EchoLength(res));
+ return res;
+} /* end ActualGap */
+
+
+/*@::EchoGap()@***************************************************************/
+/* */
+/* FULL_CHAR *EchoGap(xgap) */
+/* */
+/* Returns a static string showing the indicated xgap. */
+/* */
+/*****************************************************************************/
+#if DEBUG_ON
+
+FULL_CHAR *EchoGap(GAP *xgap)
+{ char *letter = "?ehxokt"; char c; FULL_CHAR *res;
+ char *u;
+ static int i = 0;
+ static char buff[3][20];
+ assert( mode(*xgap) <= 6, "EchoGap: mode(*xgap)" );
+ c = letter[mode(*xgap)];
+ u = nobreak(*xgap) ? "u" : "";
+ switch( units(*xgap) )
+ {
+ case 0: sprintf(buff[i], "(none)%c", c);
+ break;
+
+ case FIXED_UNIT: sprintf(buff[i], "%.1fc%c%s", (float) width(*xgap)/CM, c,u);
+ break;
+
+ case NEXT_UNIT: sprintf(buff[i], "%.1fw%c%s", (float) width(*xgap)/FR, c,u);
+ break;
+
+ case FRAME_UNIT: sprintf(buff[i], "%.1fb%c%s", (float) width(*xgap)/FR, c,u);
+ break;
+
+ case AVAIL_UNIT: sprintf(buff[i], "%.1fr%c%s", (float) width(*xgap)/FR, c,u);
+ break;
+
+ case DEG_UNIT: sprintf(buff[i], "%.1fd", (float) width(*xgap) / DG);
+ break;
+
+ default: assert(FALSE, "EchoGap: units");
+ break;
+
+ }
+ res = AsciiToFull(buff[i]);
+ i = (i + 1) % 3;
+ return res;
+} /* end EchoGap */
+#endif