/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
static char rcsid[] = "$Header: eval.c,v 2.3 84/07/19 11:47:18 guido Exp $";
/*
* B editor -- Width attribute evaluation.
*/
#include "b.h"
#include "node.h"
#include "gram.h"
#include "eval.h"
/*
* The following convention is used throughout the editor to indicate
* the sizes of objects.
* - A zero or positive `width' value means the object contains no
* linefeeds. The width is counted in characters.
* - A negative `width' means the object (or its children) contains
* at leasty one linefeed (return is treated as a linefeed here).
* The number of linefeeds is -width.
* There is no indication whether the object fits on that number of
* physical lines, as logical lines may have arbitrary length.
*
* For coordinates the following convention is used.
* (Note that, in accordance to the convention in curses(3), the
* `y' coordinate always precedes the `x' coorxdinate.)
* - `Y' is the line number, counted from the beginning of the unit.
* These are logical lines rather than physical lines.
* The first line has line number 0.
* - `X' is the column number. The first column is 0. For x < 0,
* see the important notice below.
* - `Level' is the indentation level, indicating where a new line
* would start if inserted at the current position.
* The initial `x' position of such a line is `level*TABS'.
*
* ***** IMPORTANT NOTICE *****
* A special case is x = -1. This means that the current x position is
* unknown. Further output on the same line is suppressed, until a
* linefeed is encountered. This feature is necessary because while
* calculating coordinates, when an object has width < 0, only the y
* coordinate of the end of that object is known. In this case, the
* next non-empty object MUST START WITH A LINEFEED, or it will not
* be visible on the screen (in practice, a space is sometimes present
* in the parse tree which is not shown then).
*/
/*
* Compute the (y, x) coordinates and indent level just before
* the beginning of the j'th child, if the current node starts
* at the initial values of (y, x) and level.
*/
Visible Procedure
evalcoord(n, jch, py, px, plevel)
register node n;
register int jch;
int *py;
int *px;
int *plevel;
{
node nn;
register int i;
register string *rp = noderepr(n);
register int k;
register int y = 0;
int x = *px;
int level = *plevel;
int nch = Type(n) == Tex ? 0 : nchildren(n);
if (jch > nch)
jch = nch+1;
for (i = 0; i < jch; ++i) {
if (i) {
nn = child(n, i);
k = width(nn);
if (k < 0) {
y += -k;
x = k;
}
else if (x >= 0)
x += k;
}
k = Fwidth(rp[i]);
if (k < 0) {
y += -k;
x = rp[i][0] == '\r' ? 0 : TABS*level;
x += strlen(rp[i]) - 1;
}
else {
if (x >= 0)
x += k;
if (rp[i]) {
if (rp[i][k] == '\t')
++level;
else if (rp[i][k] == '\b')
--level;
}
}
}
*py += y;
*px = x;
*plevel = level;
}
/*
* Yield the width of a piece of fixed text as found in a node's repr,
* excluding \b or \t. If \n or \r is found, -1 is returned.
* It assumes that \n or \r only occur as first
* character, and \b or \t only as last.
*/
Visible int
fwidth(str)
register string str;
{
register int c;
register int n = 0;
if (!str)
return 0;
c = str[0];
if (c == '\r' || c == '\n')
return -1;
for (; c; c = *++str)
++n;
if (n > 0) {
c = str[-1];
if (c == '\t' || c == '\b')
--n;
}
return n;
}
/*
* Evaluate the width of node n, assuming the widths of its children
* have correctly been calculated.
*/
Visible int
evalwidth(n)
register node n;
{
register int w;
register int i;
register string *rp;
register int y = 0;
register int x = 0;
register int nch;
register node nn;
rp = noderepr(n);
nch = Type(n) == Tex ? 0 : nchildren(n);
for (i = 0; i <= nch; ++i) {
if (i) {
nn = child(n, i);
w = width(nn);
if (w < 0) {
y += -w;
x = w;
}
else
x += w;
}
w = Fwidth(rp[i]);
if (w < 0) {
y += -w;
x = 0;
}
else
x += w;
}
if (y > 0)
return -y;
return x;
}