|
|
BSD 4.3
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
static char rcsid[] = "$Header: /var/lib/cvsd/repos/CSRG/43BSD/contrib/B/src/bed/node.c,v 1.1.1.1 2018/04/24 16:12:54 root Exp $";
/*
* B editor -- Parse tree and Focus stack.
*/
#include "b.h"
#include "bobj.h"
#include "node.h"
#define Register register
/* Used for registers 4-6. Define as empty macro on PDP */
/*
* Lowest level routines for 'node' data type.
*/
#define Isnode(n) ((n) && (n)->type == Nod)
#define Nchildren(n) ((n)->len)
#define Symbol(n) ((n)->n_symbol)
#define Child(n, i) ((n)->n_child[(i)-1])
#define Marks(n) ((n)->n_marks)
#define Width(n) ((n)->n_width)
/*
* Routines which are macros for the compiler but real functions for lint,
* so it will check the argument types more strictly.
*/
#ifdef lint
node
nodecopy(n)
node n;
{
return (node) copy((value) n);
}
noderelease(n)
node n;
{
release((value)n);
}
nodeuniql(pn)
node *pn;
{
uniql((value*)pn);
}
#endif lint
/*
* Allocate a new node.
*/
Visible node
newnode(nch, sym, children)
register int nch;
Register int sym;
register node children[];
{
register node n = (node) grab_node(nch); /* Must preset with zeros! */
Symbol(n) = sym;
for (; nch > 0; --nch)
Child(n, nch) = children[nch-1];
Width(n) = evalwidth(n);
return n;
}
/*
* Macros to change the fields of a node.
*/
#define Locchild(pn, i) \
(Refcnt(*(pn)) == 1 || nodeuniql(pn), &Child(*(pn), i))
#define Setmarks(pn, x) \
(Refcnt(*(pn)) == 1 || nodeuniql(pn), Marks(*(pn))=(x))
#define Setwidth(pn, w) (Refcnt(*(pn)) == 1 || nodeuniql(pn), Width(*(pn))=w)
/*
* Change a child of a node.
* Like replace(), it does not increase the reference count of n.
*/
Visible Procedure
setchild(pn, i, n)
register node *pn;
register int i;
Register node n;
{
register node *pch;
register node oldchild;
Assert(Isnode(*pn));
pch = Locchild(pn, i);
oldchild = *pch;
*pch = n;
repwidth(pn, oldchild, n);
noderelease(oldchild);
}
/*
* Lowest level routines for 'path' data type.
*/
#define NPATHFIELDS 6
#define Parent(p) ((p)->p_parent)
#define Tree(p) ((p)->p_tree)
#define Ichild(p) ((p)->p_ichild)
#define Ycoord(p) ((p)->p_ycoord)
#define Xcoord(p) ((p)->p_xcoord)
#define Level(p) ((p)->p_level)
/*
* Routines which are macros for the compiler but real functions for lint,
* so it will check the argument types more strictly.
*/
#ifdef lint
Visible path
pathcopy(p)
path p;
{
return (path) copy((value) p);
}
Visible Procedure
pathrelease(p)
path p;
{
release((value)p);
}
Visible Procedure
pathuniql(pp)
path *pp;
{
uniql((value*)pp);
}
#endif lint
/*
* Allocate a new path entry.
*/
Visible path
newpath(pa, n, i)
register path pa;
register node n;
Register int i;
{
register path p = (path) grab_path();
Parent(p) = pa;
Tree(p) = n;
Ichild(p) = i;
Ycoord(p) = Xcoord(p) = Level(p) = 0;
return p;
}
/*
* Macros to change the fields of a path entry.
*/
#define Uniqp(pp) (Refcnt(*(pp)) == 1 || pathuniql(pp))
#define Setcoord(pp, y, x, level) (Uniqp(pp), \
(*(pp))->p_ycoord = y, (*(pp))->p_xcoord = x, (*(pp))->p_level = level)
#define Locparent(pp) (Uniqp(pp), &Parent(*(pp)))
#define Loctree(pp) (Uniqp(pp), &Tree(*(pp)))
#define Addmarks(pp, x) (Uniqp(pp), \
(*(pp))->p_addmarks |= (x), (*(pp))->p_delmarks &= ~(x))
#define Delmarks(pp, x) (Uniqp(pp), \
(*(pp))->p_delmarks |= (x), (*(pp))->p_addmarks &= ~(x))
Hidden Procedure
connect(pp)
path *pp;
{
register path p = *pp;
register path pa = Parent(p);
register path *ppa;
register node n;
register node npa;
register node *pn;
node oldchild;
node *pnpa;
int i;
markbits add;
markbits del;
if (!pa)
return;
i = ichild(p);
n = Tree(p);
if (Child(Tree(pa), i) == n)
return; /* Still connected */
n = nodecopy(n);
ppa = Locparent(pp);
pnpa = Loctree(ppa);
pn = Locchild(pnpa, i);
oldchild = *pn;
*pn = n;
repwidth(pnpa, oldchild, n);
noderelease(oldchild);
add = p->p_addmarks;
del = p->p_delmarks;
if (add|del) {
p = *pp;
p->p_addmarks = 0;
p->p_delmarks = 0;
if (add)
Addmarks(ppa, add);
npa = *pnpa;
if (del) {
for (i = Nchildren(npa); i > 0; --i)
if (i != ichild(p))
del &= ~marks(Child(npa, i));
Delmarks(ppa, del);
}
Setmarks(pnpa, Marks(npa)&~del|add);
}
}
/*
* The following procedure sets the new width of node *pn when child
* oldchild is replaced by child newchild.
* This was added because the original call to evalwidth seemed to
* be the major caller of noderepr() and fwidth().
*/
Hidden Procedure
repwidth(pn, old, new)
register node *pn;
Register node old;
Register node new;
{
register int w = Width(*pn);
register int oldwidth = width(old);
register int newwidth = width(new);
if (w < 0) {
if (oldwidth > 0)
oldwidth = 0;
if (newwidth > 0)
newwidth = 0;
}
else {
Assert(oldwidth >= 0);
if (newwidth < 0) {
Setwidth(pn, newwidth);
return;
}
}
newwidth -= oldwidth;
if (newwidth)
Setwidth(pn, w + newwidth);
}
Visible Procedure
markpath(pp, new)
register path *pp;
register markbits new;
{
register node *pn;
register markbits old;
Assert(Type(Tree(*pp)) == Nod);
old = Marks(Tree(*pp));
if ((old|new) == old)
return; /* Bits already set */
pn = Loctree(pp);
Setmarks(pn, old|new);
Addmarks(pp, new&~old);
}
Visible Procedure
unmkpath(pp, del)
register path *pp;
register int del;
{
register node *pn;
register markbits old;
Assert(Type(Tree(*pp)) == Nod);
old = Marks(Tree(*pp));
if ((old&~del) == del)
return;
pn = Loctree(pp);
Setmarks(pn, old&~del);
Delmarks(pp, del&old);
}
Hidden Procedure
clearmarks(pn)
register node *pn;
{
register int i;
if (!Marks(*pn))
return;
if (Isnode(*pn)) {
Setmarks(pn, 0);
for (i = Nchildren(*pn); i > 0; --i)
clearmarks(Locchild(pn, i));
}
}
/*
* Replace the focus' tree by a new node.
* WARNING: n's reference count is not increased!
* You can also think of this as: replace(pp, n) implies noderelease(n).
* Mark bits are copied from the node being replaced.
*/
Visible Procedure
replace(pp, n)
register path *pp;
register node n;
{
register node *pn;
register markbits old;
pn = Loctree(pp);
if (Type(*pn) == Nod)
old = Marks(*pn);
else
old = 0;
noderelease(*pn);
*pn = n;
if (Type(n) == Nod) {
clearmarks(pn);
if (old)
Setmarks(pn, old);
}
else if (old)
Addmarks(pp, old);
}
Visible bool
up(pp)
register path *pp;
{
register path p = *pp;
if (!Parent(p))
return No;
connect(pp);
p = pathcopy(Parent(*pp));
pathrelease(*pp);
*pp = p;
return Yes;
}
Visible bool
downi(pp, i)
register path *pp;
register int i;
{
register node n;
auto int y;
auto int x;
auto int level;
n = Tree(*pp);
if (!Isnode(n) || i < 1 || i > Nchildren(n))
return No;
y = Ycoord(*pp);
x = Xcoord(*pp);
level = Level(*pp);
*pp = newpath(*pp, nodecopy(Child(n, i)), i);
evalcoord(n, i, &y, &x, &level);
Setcoord(pp, y, x, level);
return Yes;
}
Visible bool
downrite(pp)
register path *pp;
{
if (!Isnode(Tree(*pp)))
return No;
return downi(pp, Nchildren(Tree(*pp)));
}
Visible bool
left(pp)
register path *pp;
{
register int i;
i = ichild(*pp) - 1;
if (i <= 0)
return No;
if (!up(pp))
return No;
return downi(pp, i);
}
Visible bool
rite(pp)
register path *pp;
{
register int i;
register path pa = Parent(*pp);
i = ichild(*pp) + 1;
if (!pa || i > Nchildren(Tree(pa)))
return No;
if (!up(pp))
return No;
return downi(pp, i);
}
/*
* Highest level: small utilities.
*
* WARNING: Several of the following routines may change their argument
* even if they return No.
* HINT: Some of these routines are not used; they are included for
* completeness of the provided set of operators only. If you have
* space problems (as, e.g., on a PDP-11), you can delete the superfluous
* ones (lint will tell you which they are).
*/
Visible Procedure
top(pp)
register path *pp;
{
while (up(pp))
;
}
Visible bool
nextnode(pp)
register path *pp;
{
while (!rite(pp)) {
if (!up(pp))
return No;
}
return Yes;
}
Visible Procedure
firstleaf(pp)
register path *pp;
{
while (down(pp))
;
}
#if NOT_USED
Visible bool
nextleaf(pp)
register path *pp;
{
if (!nextnode(pp))
return No;
firstleaf(pp);
return Yes;
}
#endif NOT_USED
Visible bool
prevnode(pp)
register path *pp;
{
while (!left(pp)) {
if (!up(pp))
return No;
}
return Yes;
}
Visible Procedure
lastleaf(pp)
register path *pp;
{
while (downrite(pp))
;
}
#ifdef NOT_USED
Visible bool
prevleaf(pp)
register path *pp;
{
if (!prevnode(pp))
return No;
lastleaf(pp);
return Yes;
}
Visible bool
nextmarked(pp, x)
register path *pp;
register markbits x;
{
do {
if (!nextnode(pp))
return No;
} while (!marked(*pp, x));
while (down(pp)) {
while (!marked(*pp, x)) {
if (!rite(pp)) {
up(pp) || Abort();
return Yes;
}
}
}
return Yes;
}
#endif NOT_UED
Visible bool
firstmarked(pp, x)
register path *pp;
register markbits x;
{
while (!marked(*pp, x)) {
if (!up(pp))
return No;
}
while (down(pp)) {
while (Type(tree(*pp)) == Tex || !marked(*pp, x)) {
if (!rite(pp)) {
up(pp) || Abort();
return Yes;
}
}
}
return Yes;
}
Visible bool
prevmarked(pp, x)
register path *pp;
register markbits x;
{
do {
if (!prevnode(pp))
return No;
} while (!marked(*pp, x));
while (downrite(pp)) {
while (!marked(*pp, x)) {
if (!left(pp)) {
up(pp) || Abort();
return Yes;
}
}
}
return Yes;
}
/*
* Deliver the path length to the root.
*/
Visible Procedure
pathlength(p)
register path p;
{
register int n;
for (n = 0; p; ++n)
p = parent(p);
return n;
}
/*
* Put a C string in a trimmed location (this name should change,
* the 'official' routine of this name has quite different parameters).
*/
Visible Procedure
putintrim(pn, head, tail, str)
register value *pn;
register int head;
Register int tail;
Register string str;
{
register value v = *pn;
value w = head == 0 ? mk_text("") :
head == Length(v) ? copy(v) : trim(v, 0, Length(v) - head);
Assert(head >= 0 && tail >= 0 && head + tail <= Length(v));
if (*str)
concato(&w, str);
if (tail > 0)
concato(&w, Str(v)+(Length(v) - tail));
release(v);
*pn = w;
}
/*
* Touch the node in focus.
*/
Visible Procedure
touchpath(pp)
register path *pp;
{
nodeuniql(Loctree(pp));
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.