1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2: static char rcsid[] = "$Header: outp.c,v 2.4 85/08/22 16:05:48 timo Exp $"; 3: 4: /* 5: * B editor -- Screen management package, lower level output part. 6: */ 7: 8: #include <ctype.h> 9: 10: #include "b.h" 11: #include "bobj.h" 12: #include "node.h" 13: #include "supr.h" 14: #include "gram.h" 15: #include "cell.h" 16: 17: 18: #define SOBIT 0200 19: #define CHAR 0177 20: 21: 22: /* 23: * Variables used for communication with outfocus. 24: */ 25: 26: Hidden node thefocus; 27: Hidden environ wherebuf; 28: Hidden environ *where = &wherebuf; 29: Hidden bool realvhole; 30: Hidden int multiline; /* Height of focus */ 31: Hidden int yfocus; 32: 33: Visible int focy; /* Where the cursor must go */ 34: Visible int focx; 35: 36: 37: /* 38: * Save position of the focus for use by outnode/outfocus. 39: */ 40: 41: Visible Procedure 42: savefocus(ep) 43: register environ *ep; 44: { 45: register int sym; 46: register int w; 47: 48: realvhole = No; 49: thefocus = Nnil; 50: multiline = 0; 51: yfocus = Ycoord(ep->focus); 52: w = focoffset(ep); 53: if (w < 0) 54: yfocus += -w; 55: w = focwidth(ep); 56: if (w < 0) { 57: multiline = -w; 58: if (focchar(ep) == '\n') 59: ++yfocus; 60: else 61: ++multiline; 62: return; 63: } 64: if (ep->mode == WHOLE) { 65: sym = symbol(tree(ep->focus)); 66: if (sym == Optional) 67: ep->mode = ATBEGIN; 68: } 69: switch(ep->mode) { 70: case VHOLE: 71: if (ep->s1&1) 72: ep->mode = FHOLE; 73: case ATBEGIN: 74: case ATEND: 75: case FHOLE: 76: ritevhole(ep); 77: switch (ep->mode) { 78: case ATBEGIN: 79: case FHOLE: 80: sym = symbol(tree(ep->focus)); 81: if (sym == Hole && (ep->mode == ATBEGIN || ep->s2 == 0)) { 82: ep->mode = WHOLE; 83: break; 84: } 85: /* Fall through */ 86: case VHOLE: 87: case ATEND: 88: leftvhole(ep); 89: realvhole = 1 + ep->spflag; 90: } 91: } 92: touchpath(&ep->focus); /* Make sure it is a unique pointer */ 93: thefocus = tree(ep->focus); /* No copy; used for comparison only! */ 94: where->mode = ep->mode; 95: where->s1 = ep->s1; 96: where->s2 = ep->s2; 97: where->s3 = ep->s3; 98: where->spflag = ep->spflag; 99: } 100: 101: 102: /* 103: * Incorporate the information saved about the focus. 104: */ 105: 106: Visible Procedure 107: setfocus(tops) 108: register cell *tops; 109: { 110: register cell *p; 111: register int i; 112: 113: for (p = tops, i = 0; i < yfocus; ++i, p = p->c_link) { 114: if (!p) { 115: #ifndef NDEBUG 116: debug("[Focus lost (setfocus)]"); 117: #endif NDEBUG 118: return; 119: } 120: } 121: p->c_newvhole = realvhole; 122: i = multiline; 123: do { 124: p->c_newfocus = Yes; 125: p = p->c_link; 126: } while (--i > 0); 127: } 128: 129: 130: /* 131: * Signal that actual updata is started. 132: */ 133: 134: Visible Procedure 135: startactupdate(nofocus) 136: bool nofocus; 137: { 138: if (nofocus) { 139: multiline = 0; 140: thefocus = Nnil; 141: } 142: } 143: 144: 145: /* 146: * Signal the end of the actual update. 147: */ 148: 149: Visible Procedure 150: endactupdate() 151: { 152: } 153: 154: 155: /* 156: * Output a line of text. 157: */ 158: 159: Visible Procedure 160: outline(p, lineno) 161: register cell *p; 162: register int lineno; 163: { 164: register node n = p->c_data; 165: register int w = width(n); 166: register string buf = 167: malloc((unsigned) (p->c_newindent + 4 + (w < 0 ? linelen(n) : w))); 168: /* some 4 extra for spflag and vhole */ 169: auto string bp = buf; 170: register int i; 171: register int endarea = lineno+Space(p)-1; 172: 173: if (endarea >= winheight) 174: endarea = winheight-1; 175: for (i = p->c_newindent; i-- > 0; ) 176: *bp++ = ' '; 177: if (!p->c_newfocus) { 178: smash(&bp, n, 0); 179: *bp = 0; 180: } 181: else { 182: if (multiline) 183: smash(&bp, n, SOBIT); 184: else if (n == thefocus) 185: focsmash(&bp, n); 186: else 187: smash(&bp, n, 0); 188: *bp = 0; 189: for (bp = buf; *bp && !(*bp&SOBIT); ++bp) 190: ; 191: if (*bp&SOBIT) { 192: if (focy == Nowhere) { 193: focx = indent + bp-buf; 194: focy = lineno + focx/llength; 195: focx %= llength; 196: } 197: if (multiline <= 1 && !(bp[1]&SOBIT)) 198: *bp &= ~SOBIT; /* Clear mask if just one char in focus */ 199: } 200: } 201: trmputdata(lineno, endarea, indent, buf); 202: } 203: 204: 205: /* 206: * Smash -- produce a linear version of a node in a buffer (which had 207: * better be long enough!). The buffer pointer is moved to the end of 208: * the resulting string. 209: * Care is taken to represent the focus. 210: * Characters in the focus have their upper bit set. 211: */ 212: 213: #define Outvhole() \ 214: (where->spflag && strsmash(pbuf, " ", 0), strsmash(pbuf, "?", SOBIT)) 215: 216: Hidden Procedure 217: focsmash(pbuf, n) 218: string *pbuf; 219: node n; 220: { 221: value v; 222: string str; 223: register string *rp; 224: register int maxs2; 225: register int i; 226: register bool ok; 227: register int j; 228: register int mask; 229: 230: switch (where->mode) { 231: 232: case WHOLE: 233: smash(pbuf, n, SOBIT); 234: break; 235: 236: case ATBEGIN: 237: Outvhole(); 238: smash(pbuf, n, 0); 239: break; 240: 241: case ATEND: 242: smash(pbuf, n, 0); 243: Outvhole(); 244: break; 245: 246: case VHOLE: 247: if (!(where->s1&1)) { 248: v = (value) child(n, where->s1/2); 249: Assert(Type(v) == Tex); 250: subsmash(pbuf, Str(v), where->s2, 0); 251: Outvhole(); 252: strsmash(pbuf, Str(v) + where->s2, 0); 253: break; 254: } 255: /* Else, fall through */ 256: case FHOLE: 257: rp = noderepr(n); 258: maxs2 = 2*nchildren(n) + 1; 259: for (ok = Yes, i = 1; ok && i <= maxs2; ++i) { 260: if (i&1) { 261: if (i == where->s1) { 262: subsmash(pbuf, rp[i/2], where->s2, 0); 263: Outvhole(); 264: if (rp[i/2]) 265: strsmash(pbuf, rp[i/2] + where->s2, 0); 266: } 267: else 268: strsmash(pbuf, rp[i/2], 0); 269: } 270: else 271: ok = chismash(pbuf, n, i/2, 0); 272: } 273: break; 274: 275: case SUBRANGE: 276: rp = noderepr(n); 277: maxs2 = 2*nchildren(n) + 1; 278: for (ok = Yes, i = 1; ok && i <= maxs2; ++i) { 279: if (i&1) { 280: if (i == where->s1) { 281: subsmash(pbuf, rp[i/2], where->s2,0); 282: if (rp[i/2]) 283: subsmash(pbuf, rp[i/2] + where->s2, 284: where->s3 - where->s2 + 1, SOBIT); 285: if (rp[i/2]) 286: strsmash(pbuf, rp[i/2] + where->s3 + 1, 0); 287: } 288: else 289: strsmash(pbuf, rp[i/2], 0); 290: } 291: else if (i == where->s1) { 292: v = (value)child(n, i/2); 293: Assert(Type(v) == Tex); 294: str = Str(v); 295: subsmash(pbuf, str, where->s2, 0); 296: subsmash(pbuf, str + where->s2, where->s3 - where->s2 + 1, 297: SOBIT); 298: strsmash(pbuf, str + where->s3 + 1, 0); 299: } 300: else 301: ok = chismash(pbuf, n, i/2, 0); 302: } 303: break; 304: 305: case SUBLIST: 306: for (ok = Yes, j = where->s3; j > 0; --j) { 307: rp = noderepr(n); 308: maxs2 = 2*nchildren(n) - 1; 309: for (i = 1; ok && i <= maxs2; ++i) { 310: if (i&1) 311: strsmash(pbuf, rp[i/2], SOBIT); 312: else 313: ok = chismash(pbuf, n, i/2, SOBIT); 314: } 315: if (ok) 316: n = lastchild(n); 317: } 318: if (ok) 319: smash(pbuf, n, 0); 320: break; 321: 322: case SUBSET: 323: rp = noderepr(n); 324: maxs2 = 2*nchildren(n) + 1; 325: mask = 0; 326: for (ok = Yes, i = 1; ok && i <= maxs2; ++i) { 327: if (i == where->s1) 328: mask = SOBIT; 329: if (i&1) 330: strsmash(pbuf, rp[i/2], mask); 331: else 332: ok = chismash(pbuf, n, i/2, mask); 333: if (i == where->s2) 334: mask = 0; 335: } 336: break; 337: 338: default: 339: Abort(); 340: } 341: } 342: 343: Hidden Procedure 344: smash(pbuf, n, mask) 345: register string *pbuf; 346: register node n; 347: register int mask; 348: { 349: register string *rp; 350: register int i; 351: register int nch; 352: 353: rp = noderepr(n); 354: strsmash(pbuf, rp[0], mask); 355: nch = nchildren(n); 356: for (i = 1; i <= nch; ++i) { 357: if (!chismash(pbuf, n, i, mask)) 358: break; 359: strsmash(pbuf, rp[i], mask); 360: } 361: } 362: 363: Hidden Procedure 364: strsmash(pbuf, str, mask) 365: register string *pbuf; 366: register string str; 367: register int mask; 368: { 369: if (!str) 370: return; 371: for (; *str; ++str) { 372: if (isprint(*str) || *str == ' ') 373: **pbuf = *str|mask, ++*pbuf; 374: } 375: } 376: 377: Hidden Procedure 378: subsmash(pbuf, str, len, mask) 379: register string *pbuf; 380: register string str; 381: register int len; 382: register int mask; 383: { 384: if (!str) 385: return; 386: for (; len > 0 && *str; --len, ++str) { 387: if (isprint(*str) || *str == ' ') 388: **pbuf = *str|mask, ++*pbuf; 389: } 390: } 391: 392: 393: /* 394: * Smash a node's child. 395: * Return No if it contained a newline (to stop the parent). 396: */ 397: 398: Hidden bool 399: chismash(pbuf, n, i, mask) 400: register string *pbuf; 401: register node n; 402: register int i; 403: { 404: register node nn = child(n, i); 405: register int w; 406: 407: if (Type(nn) == Tex) { 408: strsmash(pbuf, Str((value)nn), mask); 409: return Yes; 410: } 411: w = width(nn); 412: if (w < 0 && Fw_negative(noderepr(nn)[0])) 413: return No; 414: if (nn == thefocus) 415: focsmash(pbuf, nn); 416: else 417: smash(pbuf, nn, mask); 418: return w >= 0; 419: }