/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ static char rcsid[] = "$Header: outp.c,v 2.4 85/08/22 16:05:48 timo Exp $"; /* * B editor -- Screen management package, lower level output part. */ #include #include "b.h" #include "bobj.h" #include "node.h" #include "supr.h" #include "gram.h" #include "cell.h" #define SOBIT 0200 #define CHAR 0177 /* * Variables used for communication with outfocus. */ Hidden node thefocus; Hidden environ wherebuf; Hidden environ *where = &wherebuf; Hidden bool realvhole; Hidden int multiline; /* Height of focus */ Hidden int yfocus; Visible int focy; /* Where the cursor must go */ Visible int focx; /* * Save position of the focus for use by outnode/outfocus. */ Visible Procedure savefocus(ep) register environ *ep; { register int sym; register int w; realvhole = No; thefocus = Nnil; multiline = 0; yfocus = Ycoord(ep->focus); w = focoffset(ep); if (w < 0) yfocus += -w; w = focwidth(ep); if (w < 0) { multiline = -w; if (focchar(ep) == '\n') ++yfocus; else ++multiline; return; } if (ep->mode == WHOLE) { sym = symbol(tree(ep->focus)); if (sym == Optional) ep->mode = ATBEGIN; } switch(ep->mode) { case VHOLE: if (ep->s1&1) ep->mode = FHOLE; case ATBEGIN: case ATEND: case FHOLE: ritevhole(ep); switch (ep->mode) { case ATBEGIN: case FHOLE: sym = symbol(tree(ep->focus)); if (sym == Hole && (ep->mode == ATBEGIN || ep->s2 == 0)) { ep->mode = WHOLE; break; } /* Fall through */ case VHOLE: case ATEND: leftvhole(ep); realvhole = 1 + ep->spflag; } } touchpath(&ep->focus); /* Make sure it is a unique pointer */ thefocus = tree(ep->focus); /* No copy; used for comparison only! */ where->mode = ep->mode; where->s1 = ep->s1; where->s2 = ep->s2; where->s3 = ep->s3; where->spflag = ep->spflag; } /* * Incorporate the information saved about the focus. */ Visible Procedure setfocus(tops) register cell *tops; { register cell *p; register int i; for (p = tops, i = 0; i < yfocus; ++i, p = p->c_link) { if (!p) { #ifndef NDEBUG debug("[Focus lost (setfocus)]"); #endif NDEBUG return; } } p->c_newvhole = realvhole; i = multiline; do { p->c_newfocus = Yes; p = p->c_link; } while (--i > 0); } /* * Signal that actual updata is started. */ Visible Procedure startactupdate(nofocus) bool nofocus; { if (nofocus) { multiline = 0; thefocus = Nnil; } } /* * Signal the end of the actual update. */ Visible Procedure endactupdate() { } /* * Output a line of text. */ Visible Procedure outline(p, lineno) register cell *p; register int lineno; { register node n = p->c_data; register int w = width(n); register string buf = malloc((unsigned) (p->c_newindent + 4 + (w < 0 ? linelen(n) : w))); /* some 4 extra for spflag and vhole */ auto string bp = buf; register int i; register int endarea = lineno+Space(p)-1; if (endarea >= winheight) endarea = winheight-1; for (i = p->c_newindent; i-- > 0; ) *bp++ = ' '; if (!p->c_newfocus) { smash(&bp, n, 0); *bp = 0; } else { if (multiline) smash(&bp, n, SOBIT); else if (n == thefocus) focsmash(&bp, n); else smash(&bp, n, 0); *bp = 0; for (bp = buf; *bp && !(*bp&SOBIT); ++bp) ; if (*bp&SOBIT) { if (focy == Nowhere) { focx = indent + bp-buf; focy = lineno + focx/llength; focx %= llength; } if (multiline <= 1 && !(bp[1]&SOBIT)) *bp &= ~SOBIT; /* Clear mask if just one char in focus */ } } trmputdata(lineno, endarea, indent, buf); } /* * Smash -- produce a linear version of a node in a buffer (which had * better be long enough!). The buffer pointer is moved to the end of * the resulting string. * Care is taken to represent the focus. * Characters in the focus have their upper bit set. */ #define Outvhole() \ (where->spflag && strsmash(pbuf, " ", 0), strsmash(pbuf, "?", SOBIT)) Hidden Procedure focsmash(pbuf, n) string *pbuf; node n; { value v; string str; register string *rp; register int maxs2; register int i; register bool ok; register int j; register int mask; switch (where->mode) { case WHOLE: smash(pbuf, n, SOBIT); break; case ATBEGIN: Outvhole(); smash(pbuf, n, 0); break; case ATEND: smash(pbuf, n, 0); Outvhole(); break; case VHOLE: if (!(where->s1&1)) { v = (value) child(n, where->s1/2); Assert(Type(v) == Tex); subsmash(pbuf, Str(v), where->s2, 0); Outvhole(); strsmash(pbuf, Str(v) + where->s2, 0); break; } /* Else, fall through */ case FHOLE: rp = noderepr(n); maxs2 = 2*nchildren(n) + 1; for (ok = Yes, i = 1; ok && i <= maxs2; ++i) { if (i&1) { if (i == where->s1) { subsmash(pbuf, rp[i/2], where->s2, 0); Outvhole(); if (rp[i/2]) strsmash(pbuf, rp[i/2] + where->s2, 0); } else strsmash(pbuf, rp[i/2], 0); } else ok = chismash(pbuf, n, i/2, 0); } break; case SUBRANGE: rp = noderepr(n); maxs2 = 2*nchildren(n) + 1; for (ok = Yes, i = 1; ok && i <= maxs2; ++i) { if (i&1) { if (i == where->s1) { subsmash(pbuf, rp[i/2], where->s2,0); if (rp[i/2]) subsmash(pbuf, rp[i/2] + where->s2, where->s3 - where->s2 + 1, SOBIT); if (rp[i/2]) strsmash(pbuf, rp[i/2] + where->s3 + 1, 0); } else strsmash(pbuf, rp[i/2], 0); } else if (i == where->s1) { v = (value)child(n, i/2); Assert(Type(v) == Tex); str = Str(v); subsmash(pbuf, str, where->s2, 0); subsmash(pbuf, str + where->s2, where->s3 - where->s2 + 1, SOBIT); strsmash(pbuf, str + where->s3 + 1, 0); } else ok = chismash(pbuf, n, i/2, 0); } break; case SUBLIST: for (ok = Yes, j = where->s3; j > 0; --j) { rp = noderepr(n); maxs2 = 2*nchildren(n) - 1; for (i = 1; ok && i <= maxs2; ++i) { if (i&1) strsmash(pbuf, rp[i/2], SOBIT); else ok = chismash(pbuf, n, i/2, SOBIT); } if (ok) n = lastchild(n); } if (ok) smash(pbuf, n, 0); break; case SUBSET: rp = noderepr(n); maxs2 = 2*nchildren(n) + 1; mask = 0; for (ok = Yes, i = 1; ok && i <= maxs2; ++i) { if (i == where->s1) mask = SOBIT; if (i&1) strsmash(pbuf, rp[i/2], mask); else ok = chismash(pbuf, n, i/2, mask); if (i == where->s2) mask = 0; } break; default: Abort(); } } Hidden Procedure smash(pbuf, n, mask) register string *pbuf; register node n; register int mask; { register string *rp; register int i; register int nch; rp = noderepr(n); strsmash(pbuf, rp[0], mask); nch = nchildren(n); for (i = 1; i <= nch; ++i) { if (!chismash(pbuf, n, i, mask)) break; strsmash(pbuf, rp[i], mask); } } Hidden Procedure strsmash(pbuf, str, mask) register string *pbuf; register string str; register int mask; { if (!str) return; for (; *str; ++str) { if (isprint(*str) || *str == ' ') **pbuf = *str|mask, ++*pbuf; } } Hidden Procedure subsmash(pbuf, str, len, mask) register string *pbuf; register string str; register int len; register int mask; { if (!str) return; for (; len > 0 && *str; --len, ++str) { if (isprint(*str) || *str == ' ') **pbuf = *str|mask, ++*pbuf; } } /* * Smash a node's child. * Return No if it contained a newline (to stop the parent). */ Hidden bool chismash(pbuf, n, i, mask) register string *pbuf; register node n; register int i; { register node nn = child(n, i); register int w; if (Type(nn) == Tex) { strsmash(pbuf, Str((value)nn), mask); return Yes; } w = width(nn); if (w < 0 && Fw_negative(noderepr(nn)[0])) return No; if (nn == thefocus) focsmash(pbuf, nn); else smash(pbuf, nn, mask); return w >= 0; }