aboutsummaryrefslogtreecommitdiffstats
path: root/z46.c
diff options
context:
space:
mode:
authorJeffrey H. Kingston <jeff@it.usyd.edu.au>2010-09-14 19:21:41 +0000
committerJeffrey H. Kingston <jeff@it.usyd.edu.au>2010-09-14 19:21:41 +0000
commit71bdb35d52747e6d7d9f55df4524d57c2966be94 (patch)
tree480ee5eefccc40d5f3331cc52d66f722fd19bfb9 /z46.c
parentb41263ea7578fa9742486135c762803b52794105 (diff)
downloadlout-71bdb35d52747e6d7d9f55df4524d57c2966be94.tar.gz
Lout 3.17.
git-svn-id: http://svn.savannah.nongnu.org/svn/lout/trunk@2 9365b830-b601-4143-9ba8-b4a8e2c3339c
Diffstat (limited to 'z46.c')
-rw-r--r--z46.c480
1 files changed, 480 insertions, 0 deletions
diff --git a/z46.c b/z46.c
new file mode 100644
index 0000000..7a920f4
--- /dev/null
+++ b/z46.c
@@ -0,0 +1,480 @@
+/*@z46.c:Optimal Galleys:FindOptimize()@**************************************/
+/* */
+/* 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: z46.c */
+/* MODULE: Optimal Galleys */
+/* EXTERNS: FindOptimize(), SetOptimize(), GazumpOptimize(), */
+/* CalculateOptimize(), DebugOptimize() */
+/* */
+/*****************************************************************************/
+#include "externs.h"
+
+
+/*****************************************************************************/
+/* */
+/* BOOLEAN FindOptimize(x, env) */
+/* */
+/* Object x is a CLOSURE which represents an at present unsized galley. */
+/* Return TRUE if x has an @Optimize parameter which is Yes. */
+/* */
+/*****************************************************************************/
+
+BOOLEAN FindOptimize(OBJECT x, OBJECT env)
+{ OBJECT y, link, res;
+ OBJECT bt[2], ft[2], ntarget, nenclose, crs;
+ debug1(DOG, D, "FindOptimize( %s )", EchoObject(x));
+ assert( type(x) == CLOSURE, "FindOptimize: type(x) != CLOSURE!" );
+ assert( has_target(actual(x)), "FindOptimize: x has no target!" );
+
+ /* search the parameter list of x for @Optimize */
+ res = nilobj;
+ for( link = Down(x); link != x; link = NextDown(link) )
+ { Child(y, link);
+ if( type(y) == PAR && is_optimize(actual(y)) )
+ { assert( Down(y) != y, "FindOptimize: Down(PAR)!" );
+ Child(res, Down(y));
+ res = CopyObject(res, &fpos(x));
+ break;
+ }
+ }
+
+ /* search the children list of actual(x) for a default value of @Target */
+ if( res == nilobj )
+ for( link = Down(actual(x)); link != actual(x); link = NextDown(link) )
+ { Child(y, link);
+ if( is_optimize(y) )
+ { res = CopyObject(sym_body(y), &fpos(x));
+ break;
+ }
+ }
+
+ /* should have found it by now */
+ assert( res != nilobj, "FindOptimize: res == nilobj!" );
+
+ /* manifest and tidy the parameter, return TRUE if Yes */
+ bt[COLM] = ft[COLM] = bt[ROWM] = ft[ROWM] = ntarget = nenclose = crs = nilobj;
+ res = Manifest(res, env, &save_style(x), bt, ft, &ntarget, &crs, TRUE, FALSE,
+ &nenclose, FALSE);
+ res = ReplaceWithTidy(res, TRUE);
+ if( !is_word(type(res)) )
+ { Error(46, 1, "unable to evaluate %s parameter, assuming value is No",
+ WARN, &fpos(x), KW_OPTIMIZE);
+ debug2(DOG, D, "FindOptimize returning FALSE; found %s %s",
+ Image(type(res)), EchoObject(res));
+ return FALSE;
+ }
+ else if( StringEqual(string(res), AsciiToFull("Yes")) )
+ { debug0(DOG, D, "FindOptimize returning TRUE");
+ return TRUE;
+ }
+ else if( StringEqual(string(res), AsciiToFull("No")) )
+ { debug0(DOG, D, "FindOptimize returning FALSE");
+ return FALSE;
+ }
+ else
+ { Error(46, 2, "value of %s operator is neither Yes nor No, assuming No",
+ WARN, &fpos(x), KW_OPTIMIZE);
+ debug1(DOG, D, "FindOptimize returning FALSE (found WORD %s)", string(res));
+ return FALSE;
+ }
+} /* end FindOptimize */
+
+
+/*****************************************************************************/
+/* */
+/* SetOptimize(hd, style) */
+/* */
+/* Initialize the optimization data of galley hd. Search the cross ref */
+/* database for information about its fate on the previous run. */
+/* */
+/*****************************************************************************/
+
+void SetOptimize(OBJECT hd, STYLE *style)
+{ FULL_CHAR buff[MAX_BUFF], seq[MAX_BUFF];
+ OBJECT res, y, link, z; FILE_NUM dfnum; long dfpos, cont; int dlnum;
+ debug2(DOG, D, "SetOptimize(%s, %s)", SymName(actual(hd)), EchoStyle(style));
+
+ /* set opt_counts(hd) to result of previous run, if any */
+ StringCopy(buff, SymName(actual(hd)));
+ StringCat(buff, AsciiToFull("."));
+ StringCat(buff, StringInt(line_num(fpos(hd))));
+ if( DbRetrieve(OldCrossDb, FALSE, OptGallSym, buff, seq, &dfnum,
+ &dfpos, &dlnum, &cont) )
+ {
+ SwitchScope(nilobj);
+ res = ReadFromFile(dfnum, dfpos, dlnum);
+ UnSwitchScope(nilobj);
+ assert( res != nilobj, "SetOptimize: res == nilobj!" );
+ assert( type(res) == CLOSURE, "SetOptimize: type(res) != CLOSURE!" );
+ assert( actual(res) == OptGallSym, "SetOptimize: actual(res) != Opt!" );
+ assert( Down(res) != res, "SetOptimize: Down(res) == res!" );
+ Child(y, Down(res));
+ assert( type(y) == PAR, "SetOptimize: type(y) != PAR!" );
+ Child(y, Down(y));
+ assert( type(y) == ACAT, "SetOptimize: type(y) != ACAT!" );
+ y = ReplaceWithTidy(y, FALSE);
+ opt_hyph(hd) = FALSE;
+ assert( type(y) == ACAT, "SetOptimize: type(y) != ACAT (2)!" );
+ for( link = y; NextDown(link) != y; link = NextDown(link) )
+ { Child(z, NextDown(link));
+ if( type(z) == GAP_OBJ )
+ { DisposeChild(NextDown(link));
+ link = PrevDown(link);
+ }
+ else if( is_word(type(z)) )
+ { if( StringEqual(string(z), AsciiToFull("h")) )
+ { opt_hyph(hd) = TRUE;
+ DisposeChild(NextDown(link));
+ link = PrevDown(link);
+ }
+ else
+ { int num = 0;
+ sscanf( (char *) string(z), "%d", &num);
+ assert( num > 0, "SetOptimize: num <= 0!" );
+ comp_count(z) = num;
+ }
+ }
+ else
+ { assert( FALSE, "SetOptimize: type(z)!" );
+ }
+ }
+ DeleteLink(Up(y));
+ DisposeObject(res);
+ opt_counts(hd) = y;
+ }
+ else opt_counts(hd) = nilobj;
+
+ /* set up first opt_comps_permitted value */
+ if( opt_counts(hd) != nilobj && Down(opt_counts(hd)) != opt_counts(hd) )
+ { Child(z, Down(opt_counts(hd)));
+ opt_comps_permitted(hd) = comp_count(z) - 1;
+ DisposeChild(Up(z));
+ }
+ else opt_comps_permitted(hd) = MAX_FILES; /* a large number */
+ debug1(DOG, D, " initial permitted = %2d", opt_comps_permitted(hd));
+
+ /* set opt_components(hd) and opt_constraints(hd) for storing this run */
+ New(opt_components(hd), ACAT);
+ opt_gazumped(hd) = FALSE;
+ New(opt_constraints(hd), ACAT);
+ StyleCopy(save_style(opt_components(hd)), *style);
+ if( gall_dir(hd) == ROWM )
+ hyph_style(save_style(opt_components(hd))) = HYPH_OFF;
+
+ debug0(DOG, D, "SetOptimize returning:");
+ ifdebug(DOG, D, DebugOptimize(hd));
+} /* end SetOptimize */
+
+
+/*****************************************************************************/
+/* */
+/* GazumpOptimize(hd, dest) */
+/* */
+/* Optimizing galley hd, currently attached to @Galley dest, is to be */
+/* gazumped by some other galley. Record the current size constraint and */
+/* add &1rt {} to the list of components. */
+/* */
+/*****************************************************************************/
+
+void GazumpOptimize(OBJECT hd, OBJECT dest)
+{ OBJECT g, tmp, junk, prnt;
+
+ debug2(DOG, D, "GazumpOptimize(%s, %s)", SymName(actual(hd)),
+ EchoObject(dest));
+ assert( type(hd) == HEAD, "GazumpOptimize: type(hd) != HEAD!" );
+ assert( opt_components(hd) != nilobj, "GazumpOptimize: opt_c!" );
+
+ /* record the size of this just-completed target area for hd */
+ New(tmp, WIDE);
+ if( (gall_dir(hd) == COLM && external_hor(dest)) ||
+ (gall_dir(hd) == COLM && external_hor(dest)) )
+ { SetConstraint(constraint(tmp), MAX_FULL_LENGTH, MAX_FULL_LENGTH, MAX_FULL_LENGTH);
+ }
+ else
+ { Parent(prnt, Up(dest));
+ Constrained(prnt, &constraint(tmp), gall_dir(hd), &junk);
+ }
+ Link(opt_constraints(hd), tmp);
+ debug2(DOG, D, "GazumpOptimize(%s) adding constraint %s",
+ SymName(actual(hd)), EchoConstraint(&constraint(tmp)));
+
+ /* optimizing galley is being gazumped; record this as &1rt {} &1c */
+ if( LastDown(opt_components(hd)) != opt_components(hd) )
+ { Child(g, LastDown(opt_components(hd)));
+ assert( type(g) == GAP_OBJ, "FlushGalley: type(g) != GAP_OBJ!" );
+
+ /* ***
+ SetGap(gap(g), FALSE, FALSE, TRUE, FRAME_UNIT, EDGE_MODE, 2 * FR);
+ if( Down(g) == g )
+ { junk = MakeWord(WORD, AsciiToFull("2b"), &fpos(g));
+ Link(g, junk);
+ }
+ *** */
+
+ /* first we overwrite whatever is there now by &1rt */
+ SetGap(gap(g), FALSE, FALSE, TRUE, AVAIL_UNIT, TAB_MODE, 1 * FR);
+ if( Down(g) != g ) DisposeChild(Down(g));
+ tmp = MakeWord(WORD, AsciiToFull("1rt"), &fpos(g));
+ Link(g, tmp);
+
+ /* next we add an empty word */
+ tmp = MakeWord(WORD, STR_EMPTY, &fpos(g));
+ back(tmp, COLM) = fwd(tmp, COLM) = 0;
+ back(tmp, ROWM) = fwd(tmp, ROWM) = 0;
+ word_font(tmp) = word_colour(tmp) = 0;
+ word_language(tmp) = word_hyph(tmp) = 0;
+ Link(opt_components(hd), tmp);
+
+ /* finally we add &1c */
+ New(g, GAP_OBJ);
+ hspace(g) = 1; vspace(g) = 0;
+ FposCopy(fpos(g), fpos(tmp));
+ SetGap(gap(g), FALSE, FALSE, TRUE, FIXED_UNIT, EDGE_MODE, 1 * CM);
+ tmp = MakeWord(WORD, AsciiToFull("1c"), &fpos(g));
+ Link(g, tmp);
+ Link(opt_components(hd), g);
+
+ opt_gazumped(hd) = TRUE;
+ debug2(DOG, D, "GazumpOptimize(%s) new gap is %s",
+ SymName(actual(hd)), EchoGap(&gap(g)));
+ }
+
+ /* refresh the number of comps permitted into the next target */
+ if( opt_counts(hd) != nilobj && Down(opt_counts(hd)) != opt_counts(hd) )
+ { Child(tmp, Down(opt_counts(hd)));
+ opt_comps_permitted(hd) += comp_count(tmp) - 1;
+ DisposeChild(Up(tmp));
+ }
+ else opt_comps_permitted(hd) = MAX_FILES;
+
+ debug1(DOG, D, "GazumpOptimize returning, permitted = %2d",
+ opt_comps_permitted(hd));
+} /* end GazumpOptimize */
+
+
+/*****************************************************************************/
+/* */
+/* CalculateOptimize(hd) */
+/* */
+/* Calculate the optimal break for galley hd and write the result into */
+/* the cross reference database. */
+/* */
+/*****************************************************************************/
+
+void CalculateOptimize(OBJECT hd)
+{ OBJECT z, y, ylink, og, og_par, para, link, wd, g, last;
+ int count, compcount; FULL_CHAR buff[MAX_BUFF];
+ FILE_NUM fnum; int write_pos, write_lnum; BOOLEAN hyph_used;
+ debug1(DOG, D, "CalculateOptimize(%s)", SymName(actual(hd)));
+
+ /* delete the concluding GAP_OBJ stuck in by Promote() */
+ assert( LastDown(opt_components(hd)) != opt_components(hd), "CO!" );
+ Child(last, LastDown(opt_components(hd)));
+ assert( type(last) == GAP_OBJ, "CalculateOptimize: type(last)!" );
+ DisposeChild(Up(last));
+ ifdebug(DOG, D, DebugOptimize(hd));
+
+ /* break the paragraph; don't let user see any error messages */
+ assert( opt_constraints(hd) != nilobj, "KillGalley: no opt_constraints!" );
+ assert( Down(opt_constraints(hd)) != opt_constraints(hd), "KillGalleyo!" );
+ /* *** no longer needed since z14 doesn't refer to these fields
+ back(opt_components(hd), COLM) = 0;
+ fwd(opt_components(hd), COLM) = MAX_FULL_LENGTH;
+ *** */
+ Child(y, LastDown(opt_constraints(hd)));
+ EnterErrorBlock(FALSE);
+ opt_components(hd) = FillObject(opt_components(hd), &constraint(y),
+ opt_constraints(hd), FALSE, FALSE, TRUE, &hyph_used);
+ LeaveErrorBlock(FALSE);
+ debug1(DOG, D, "after breaking (%shyph_used):", hyph_used ? "" : "not ");
+ ifdebug(DOG, D, DebugOptimize(hd));
+
+ /* quit if one line only */
+ if( type(opt_components(hd)) != VCAT ||
+ Down(opt_components(hd)) == LastDown(opt_components(hd)) )
+ {
+ debug0(DOG, D, "CalculateOptimize returning (one target only)");
+ return;
+ }
+
+ /* construct a new @OptGall symbol */
+ New(og, CLOSURE);
+ actual(og) = OptGallSym;
+ FposCopy(fpos(og), fpos(hd));
+ New(og_par, PAR);
+ actual(og_par) = ChildSym(OptGallSym, RPAR);
+ Link(og, og_par);
+ New(para, ACAT);
+ Link(og_par, para);
+
+ /* begin with "h" if hyphenation was used */
+ if( hyph_used )
+ { wd = MakeWord(WORD, AsciiToFull("h"), &fpos(hd));
+ Link(para, wd);
+ }
+
+ /* attach words showing the number of components per target */
+ compcount = 0;
+ for( link = Down(opt_components(hd)); link != opt_components(hd);
+ link = NextDown(link) )
+ { Child(y, link);
+ if( type(y) != ACAT ) continue;
+
+ /* let wd be a word containing the number of components in this target */
+ count = 0;
+ for( ylink = Down(y); ylink != y; ylink = NextDown(ylink) )
+ { Child(z, ylink);
+ if( type(z) != GAP_OBJ ) count++;
+ }
+ wd = MakeWord(WORD, StringInt(count), &fpos(y));
+
+ /* link wd to para, prepended by a gap if not first */
+ if( Down(para) != para )
+ { New(g, GAP_OBJ);
+ SetGap(gap(g), FALSE, FALSE, TRUE, FIXED_UNIT, EDGE_MODE, 1*EM);
+ if( ++compcount % 20 == 0 )
+ { hspace(g) = 0;
+ vspace(g) = 1;
+ }
+ else
+ { hspace(g) = 1;
+ vspace(g) = 0;
+ }
+ Link(para, g);
+ }
+ Link(para, wd);
+ }
+ debug2(DOG, D, "CalculateOptimize(%s) made object %s",
+ SymName(actual(hd)), EchoObject(og));
+
+ /* dispose the optimizing data structures */
+ DisposeObject(opt_components(hd));
+ opt_components(hd) = nilobj;
+ DisposeObject(opt_constraints(hd));
+ opt_constraints(hd) = nilobj;
+
+ /* write result onto cross-reference database */
+ if( AllowCrossDb )
+ {
+ /* construct a suitable tag for this galley's entry */
+ StringCopy(buff, SymName(actual(hd)));
+ StringCat(buff, AsciiToFull("."));
+ StringCat(buff, StringInt(line_num(fpos(hd))));
+ fnum = DatabaseFileNum(&fpos(hd));
+ AppendToFile(og, fnum, &write_pos, &write_lnum);
+ DbInsert(NewCrossDb, FALSE, OptGallSym, buff, &fpos(hd),
+ STR_ZERO, fnum, write_pos, write_lnum, FALSE);
+ }
+ debug0(DOG, D, "CalculateOptimize returning.");
+}
+
+#if DEBUG_ON
+/*****************************************************************************/
+/* */
+/* DebugOptimizedAcat(x) */
+/* */
+/* Debug output of one line of optimized ACAT. */
+/* */
+/*****************************************************************************/
+
+static void DebugOptimizedAcat(OBJECT x)
+{ OBJECT link, y;
+ assert( type(x) == ACAT, "DebugOptimizedAcat!" );
+ for( link = Down(x); link != x; link = NextDown(link) )
+ { Child(y, link);
+ if( type(y) == GAP_OBJ )
+ { debug1(DOG, D, " GAP_OBJ %s", EchoGap(&gap(y)));
+ }
+ else if( is_word(type(y)) )
+ { debug2(DOG, D, " word (%s, %s)", EchoLength(back(y, COLM)),
+ EchoLength(fwd(y, COLM)));
+ }
+ else
+ { debug1(DOG, D, " %s", Image(type(y)));
+ }
+ }
+} /* end DebugOptimizedAcat */
+
+
+/*****************************************************************************/
+/* */
+/* DebugOptimize(hd) */
+/* */
+/* Debug output of optimized galley hd. */
+/* */
+/*****************************************************************************/
+
+void DebugOptimize(OBJECT hd)
+{ OBJECT link, y;
+
+ assert( opt_components(hd) != nilobj, "DebugOptimize!");
+ debug3(DOG, D, "Optimized Galley %s %sinto %s", SymName(actual(hd)),
+ gall_dir(hd) == COLM ? "horizontally " : "", SymName(whereto(hd)));
+
+ /* print components */
+ /* *** believe this now ***
+ if( type(opt_components(hd)) == ACAT )
+ DebugOptimizedAcat(opt_components(hd));
+ else if( type(opt_components(hd)) == VCAT )
+ {
+ for( link = Down(opt_components(hd)); link != opt_components(hd);
+ link = NextDown(link) )
+ {
+ Child(y, link);
+ if( type(y) == ACAT ) DebugOptimizedAcat(y);
+ debug0(DOG, D, "----------------");
+ }
+ }
+ else debug1(DOG, D, "? %s ?", Image(type(opt_components(hd))));
+ *** */
+ debug0(DOG, D, "components:");
+ ifdebug(DOG, D, DebugObject(opt_components(hd)));
+ debug0(DOG, D, "");
+
+ /* print constraints */
+ debug0(DOG, D, "constraints:");
+ for( link = Down(opt_constraints(hd)); link != opt_constraints(hd);
+ link = NextDown(link) )
+ {
+ Child(y, link);
+ debug1(DOG, D, "%s", EchoConstraint(&constraint(y)));
+ }
+ debug0(DOG, D, "");
+
+ /* print counts */
+ debug0(DOG, D, "counts");
+ if( opt_counts(hd) != nilobj )
+ {
+ if( opt_hyph(hd) )
+ fprintf(stderr, "hyph");
+ for( link = Down(opt_counts(hd)); link != opt_counts(hd);
+ link = NextDown(link) )
+ { Child(y, link);
+ fprintf(stderr, " %d", comp_count(y));
+ }
+ fprintf(stderr, "\n");
+ }
+ debug0(DOG, D, "");
+} /* end DebugOptimize */
+#endif