|
|
1.1 ! root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ ! 2: static char rcsid[] = "$Header: que1.c,v 2.4 84/10/26 12:04:28 guido Exp $"; ! 3: ! 4: /* ! 5: * B editor -- Manipulate queues of nodes, lower levels. ! 6: */ ! 7: ! 8: #include "b.h" ! 9: #include "feat.h" ! 10: #include "bobj.h" ! 11: #include "node.h" ! 12: #include "supr.h" ! 13: #include "queu.h" ! 14: #include "gram.h" ! 15: ! 16: #include <ctype.h> ! 17: ! 18: ! 19: value grab_com(); ! 20: ! 21: ! 22: /* ! 23: * Append queue 2 to the end of queue 1. ! 24: */ ! 25: ! 26: Visible Procedure ! 27: joinqueues(pq, q) ! 28: register queue *pq; ! 29: register queue q; ! 30: { ! 31: if (emptyqueue(q)) ! 32: return; ! 33: while (*pq) { ! 34: if (Refcnt(*pq) > 1) ! 35: uniql((value*)pq); ! 36: pq = &(*pq)->q_link; ! 37: } ! 38: *pq = q; ! 39: } ! 40: ! 41: ! 42: /* ! 43: * Prepend a node to a queue ("push"). ! 44: * Empty strings and Optional holes are silently discarded. ! 45: */ ! 46: ! 47: Visible Procedure ! 48: preptoqueue(n, pq) ! 49: node n; ! 50: register queue *pq; ! 51: { ! 52: register queue q; ! 53: ! 54: if (Type(n) == Tex) { ! 55: int len = Length((value)n); ! 56: if (len == 0) ! 57: return; ! 58: n = nodecopy(n); ! 59: } ! 60: else { /* Avoid Optional holes */ ! 61: if (symbol(n) == Optional) ! 62: return; ! 63: n = nodecopy(n); ! 64: } ! 65: q = (queue) grab_com(2); ! 66: q->q_data = n; ! 67: q->q_link = *pq; ! 68: *pq = q; ! 69: } ! 70: ! 71: ! 72: /* ! 73: * Append a node to the end of a queue (same extras as preptoqueue). ! 74: */ ! 75: ! 76: Visible Procedure ! 77: addtoqueue(pq, n) ! 78: register queue *pq; ! 79: register node n; ! 80: { ! 81: auto queue q = Qnil; ! 82: ! 83: preptoqueue(n, &q); ! 84: joinqueues(pq, q); ! 85: } ! 86: ! 87: ! 88: /* ! 89: * Push a string onto a queue. ! 90: */ ! 91: ! 92: Visible Procedure ! 93: stringtoqueue(str, pq) ! 94: register string str; ! 95: register queue *pq; ! 96: { ! 97: register value v; ! 98: ! 99: if (str == NULL) ! 100: return; ! 101: v = mk_text(str); ! 102: preptoqueue((node) v, pq); ! 103: release(v); ! 104: } ! 105: ! 106: ! 107: /* ! 108: * Append a string to a queue. ! 109: */ ! 110: ! 111: Visible Procedure ! 112: addstringtoqueue(pq, str) ! 113: register queue *pq; ! 114: register string str; ! 115: { ! 116: register value v = mk_text(str); ! 117: ! 118: addtoqueue(pq, (node) v); ! 119: release(v); ! 120: } ! 121: ! 122: ! 123: /* ! 124: * Get the first node of a queue and delink it ("pop"). ! 125: */ ! 126: ! 127: Visible node ! 128: queuebehead(pq) ! 129: register queue *pq; ! 130: { ! 131: register node n; ! 132: register queue q = *pq; ! 133: ! 134: Assert(q); ! 135: ! 136: n = nodecopy(q->q_data); ! 137: *pq = qcopy(q->q_link); ! 138: qrelease(q); ! 139: return n; ! 140: } ! 141: ! 142: ! 143: /* ! 144: * Split a node in successive queue elements which are pushed ! 145: * on the queue using preptoqueue. ! 146: * 'Atomic' nodes (texts and holes) are pushed unadorned. ! 147: */ ! 148: ! 149: Visible Procedure ! 150: splitnode(n, pq) ! 151: register node n; ! 152: register queue *pq; ! 153: { ! 154: register node nn; ! 155: register string *rp; ! 156: register int i; ! 157: register int sym; ! 158: ! 159: if (Type(n) == Tex) { ! 160: preptoqueue(n, pq); ! 161: return; ! 162: } ! 163: sym = symbol(n); ! 164: if (sym == Optional) ! 165: return; ! 166: if (sym == Hole) { ! 167: preptoqueue(n, pq); ! 168: return; ! 169: } ! 170: ! 171: rp = noderepr(n); ! 172: for (i = nchildren(n); i >= 0; --i) { ! 173: if (rp[i] && rp[i][0]) ! 174: stringtoqueue(rp[i], pq); ! 175: if (i) { ! 176: nn = child(n, i); ! 177: if (Type(nn) == Tex || symbol(nn) != Optional) ! 178: preptoqueue(nn, pq); ! 179: } ! 180: } ! 181: } ! 182: ! 183: ! 184: /* ! 185: * Substitute the focus for its parent, appending the remainder of ! 186: * the parent to the queue. ! 187: * The focus must be the first child and not preceded by fixed text. ! 188: * The focus must be allowed in the place of its parent. ! 189: * If any of these conditions is not met, No is returned and nothing ! 190: * is changed. ! 191: */ ! 192: ! 193: Visible bool ! 194: resttoqueue(pp, pq) ! 195: register path *pp; ! 196: register queue *pq; ! 197: { ! 198: auto queue q = Qnil; ! 199: register path pa = parent(*pp); ! 200: register node n = tree(*pp); ! 201: register int sym = symbol(n); ! 202: /* register markbits x; */ ! 203: ! 204: if (!pa || ichild(*pp) != 1 ! 205: || fwidth(noderepr(tree(pa))[0]) != 0 || !allowed(pa, sym)) ! 206: return No; ! 207: ! 208: n = nodecopy(n); ! 209: /* x = marks(n); */ ! 210: up(pp) || Abort(); ! 211: splitnode(tree(*pp), &q); ! 212: noderelease(queuebehead(&q)); ! 213: replace(pp, n); ! 214: /* if (x) { */ ! 215: /* markpath(pp, x); */ /* Actually, should restore all n's marks? */ ! 216: /* } */ ! 217: joinqueues(pq, q); ! 218: return Yes; ! 219: } ! 220: ! 221: ! 222: /* ! 223: * Like resttoqueue, but exactly from current position in fixed text. ! 224: * Also, it cannot fail. ! 225: */ ! 226: ! 227: Visible Procedure ! 228: nosuggtoqueue(ep, pq) ! 229: register environ *ep; ! 230: queue *pq; ! 231: { ! 232: auto queue q = Qnil; ! 233: register int i; ! 234: register string *rp; ! 235: register node n; ! 236: register node nn; ! 237: register int sym; ! 238: string str; ! 239: ! 240: if (issuggestion(ep)) ! 241: return; ! 242: Assert((ep->mode == FHOLE || ep->mode == VHOLE) && (ep->s1&1)); ! 243: ! 244: n = tree(ep->focus); ! 245: rp = noderepr(n); ! 246: for (i = nchildren(n); i > ep->s1/2; --i) { ! 247: if (!Fw_zero(rp[i])) ! 248: stringtoqueue(rp[i], &q); ! 249: nn = child(n, i); ! 250: sym = symbol(nn); ! 251: if (sym != Optional) { ! 252: preptoqueue(nn, &q); ! 253: if (sym != Hole) { ! 254: s_downi(ep, i); ! 255: delfocus(&ep->focus); ! 256: s_up(ep); ! 257: } ! 258: } ! 259: } ! 260: str = rp[i]; ! 261: if (str && str[ep->s2]) /* Push partial first text */ ! 262: stringtoqueue(str + ep->s2, &q); ! 263: joinqueues(pq, q); ! 264: } ! 265: ! 266: ! 267: /* ! 268: * Check whether the remainder of the current node is all suggestion. ! 269: */ ! 270: ! 271: Visible bool ! 272: issuggestion(ep) ! 273: register environ *ep; ! 274: { ! 275: register node n; ! 276: register int nch; ! 277: register int sym; ! 278: register int i; ! 279: ! 280: if (ep->mode != VHOLE && ep->mode != FHOLE || !(ep->s1&1)) ! 281: return No; /* Actually wrong call? */ ! 282: ! 283: n = tree(ep->focus); ! 284: nch = nchildren(n); ! 285: for (i = ep->s1/2 + 1; i <= nch; ++i) { ! 286: sym = symbol(child(n, i)); ! 287: if (sym != Hole && sym != Optional) ! 288: return No; ! 289: } ! 290: return Yes; ! 291: } ! 292: ! 293: ! 294: /* ! 295: * See if a node fits in a hole. ! 296: */ ! 297: ! 298: Visible bool ! 299: fitnode(pp, n) ! 300: register path *pp; ! 301: register node n; ! 302: { ! 303: if (!allowed(*pp, symbol(n))) ! 304: return No; ! 305: replace(pp, nodecopy(n)); ! 306: return Yes; ! 307: } ! 308: ! 309: ! 310: /* ! 311: * Fit a string in a hole. ! 312: * Returns the number of characters consumed. ! 313: * (This does not have to be the maximum possible, but a reasonable attempt ! 314: * is made. If the internal buffer is exhausted, it leaves the rest for ! 315: * another call.) ! 316: */ ! 317: ! 318: Visible int ! 319: fitstring(pp, str, alt_c) ! 320: register path *pp; ! 321: register string str; ! 322: int alt_c; ! 323: { ! 324: environ dummyenv; ! 325: register node n; ! 326: register int ich; ! 327: register int len; ! 328: register string cp; ! 329: char buf[1024]; ! 330: ! 331: Assert(str); ! 332: if (!str[0]) ! 333: return 0; ! 334: if (!insguess(pp, str[0], &dummyenv)) { ! 335: if (!alt_c) ! 336: return 0; ! 337: if (!insguess(pp, alt_c, &dummyenv)) ! 338: return 0; ! 339: } ! 340: if (Type(tree(*pp)) == Tex) ! 341: up(pp) || Abort(); ! 342: if (dummyenv.mode == FHOLE) { ! 343: cp = noderepr(tree(*pp))[0]; ! 344: len = 1; ! 345: if (cp) { ! 346: ++str; ! 347: ++cp; ! 348: while (*str >= ' ' && *str == *cp) { ! 349: ++len; ! 350: ++str; ! 351: ++cp; ! 352: } ! 353: } ! 354: return len; ! 355: } ! 356: if (dummyenv.mode == VHOLE) { ! 357: buf[0] = str[0]; ! 358: ++str; ! 359: len = 1; ! 360: n = tree(*pp); ! 361: ich = dummyenv.s1/2; ! 362: while (*str && mayinsert(n, ich, len, *str) && len < sizeof buf - 1) { ! 363: buf[len] = *str; ! 364: ++str; ! 365: ++len; ! 366: } ! 367: if (len > 1) { ! 368: buf[len] = 0; ! 369: downi(pp, ich) || Abort(); ! 370: replace(pp, (node) mk_text(buf)); ! 371: up(pp) || Abort(); ! 372: } ! 373: return len; ! 374: } ! 375: return 1; ! 376: } ! 377: ! 378: ! 379: /* ! 380: * Set the focus position (some VHOLE/FHOLE setting, probably) ! 381: * at the 'len'th character from the beginning of the current node. ! 382: * This may involve going to a child or moving beyond the current subtree. ! 383: * Negative 'len' values may be given to indicate negative widths; ! 384: * this is implemented incomplete. ! 385: */ ! 386: ! 387: Visible Procedure ! 388: fixfocus(ep, len) ! 389: register environ *ep; ! 390: register int len; ! 391: { ! 392: node nn; ! 393: register node n = tree(ep->focus); ! 394: register string *rp; ! 395: register int i = 0; ! 396: register int nch; ! 397: register int w; ! 398: ! 399: if (Type(n) == Tex) { ! 400: w = Length((value)n); ! 401: Assert(w >= len && len >= 0); ! 402: if (w > len) ! 403: ep->spflag = No; ! 404: ep->mode = VHOLE; ! 405: ep->s1 = ichild(ep->focus) * 2; ! 406: ep->s2 = len; ! 407: s_up(ep); ! 408: return; ! 409: } ! 410: nch = nchildren(n); ! 411: w = width(n); ! 412: if (len > w && w >= 0) { ! 413: i = ichild(ep->focus); /* Change initial condition for for-loop */ ! 414: if (!up(&ep->focus)) { ! 415: ep->mode = ATEND; ! 416: return; ! 417: } ! 418: higher(ep); ! 419: n = tree(ep->focus); ! 420: } ! 421: ! 422: rp = noderepr(n); ! 423: for (; i <= nch; ++i) { ! 424: if (i) { ! 425: nn = child(n, i); ! 426: w = width(nn); ! 427: if (w < 0 || w >= len && len >= 0) { ! 428: s_downi(ep, i); ! 429: fixfocus(ep, len); ! 430: return; ! 431: } ! 432: if (len >= 0) ! 433: len -= w; ! 434: } ! 435: w = Fwidth(rp[i]); ! 436: if (w >= len && len >= 0) { ! 437: if (w > len) ! 438: ep->spflag = No; ! 439: ep->mode = FHOLE; ! 440: ep->s1 = 2*i + 1; ! 441: ep->s2 = len; ! 442: return; ! 443: } ! 444: else if (w < 0) ! 445: len = 0; ! 446: else ! 447: len -= w; ! 448: } ! 449: ep->mode = ATEND; ! 450: } ! 451: ! 452: ! 453: /* ! 454: * Apply, if possible, a special fix relating to spaces: ! 455: * when a space has been interpreted as joining character ! 456: * and we end up in the following hole, but we don't succeed ! 457: * in filling the hole; it is then tried to delete the hole ! 458: * and the space. ! 459: * Usually this doesn't occur, but it may occur when inserting ! 460: * after a space that was already fixed on the screen but now ! 461: * deserves re-interpretation. ! 462: */ ! 463: ! 464: Visible bool ! 465: spacefix(ep) ! 466: environ *ep; ! 467: { ! 468: path pa; ! 469: node n; ! 470: string *rp; ! 471: ! 472: if (ichild(ep->focus) != 2 || symbol(tree(ep->focus)) != Hole) ! 473: return No; ! 474: pa = parent(ep->focus); ! 475: n = tree(pa); ! 476: rp = noderepr(n); ! 477: if (!Fw_zero(rp[0]) || Fwidth(rp[1]) != 1 || rp[1][0] != ' ') ! 478: return No; ! 479: n = firstchild(n); ! 480: if (!allowed(pa, symbol(n))) ! 481: return No; ! 482: s_up(ep); ! 483: replace(&ep->focus, nodecopy(n)); ! 484: ep->mode = ATEND; ! 485: ep->spflag = Yes; ! 486: return Yes; ! 487: } ! 488: ! 489: ! 490: /* ! 491: * Prepend a subset of a node to a queue. ! 492: */ ! 493: ! 494: Visible Procedure ! 495: subsettoqueue(n, s1, s2, pq) ! 496: register node n; ! 497: register int s1; ! 498: register int s2; ! 499: register queue *pq; ! 500: { ! 501: register string *rp = noderepr(n); ! 502: ! 503: for (; s2 >= s1; --s2) { ! 504: if (s2&1) ! 505: stringtoqueue(rp[s2/2], pq); ! 506: else ! 507: preptoqueue(child(n, s2/2), pq); ! 508: } ! 509: } ! 510: ! 511: #ifdef SHOWBUF ! 512: ! 513: /* ! 514: * Produce flat text out of a queue's first line, to show it on screen. ! 515: */ ! 516: ! 517: Visible string ! 518: querepr(qv) ! 519: value qv; ! 520: { ! 521: queue q = (queue)qv; ! 522: node n; ! 523: static char buf[1000]; /***** Cannot overflow? *****/ ! 524: string cp; ! 525: string sp; ! 526: string *rp; ! 527: int nch; ! 528: int i; ! 529: int len; ! 530: ! 531: cp = buf; ! 532: for (; q; q = q->q_link) { ! 533: n = q->q_data; ! 534: if (Type(n) == Tex) { ! 535: for (sp = Str((value) n); cp < buf+80 && *sp; ++sp) { ! 536: if (!isprint(*sp) && *sp != ' ') ! 537: break; ! 538: *cp++ = *sp; ! 539: } ! 540: if (*sp == '\n') { ! 541: if (!emptyqueue(q->q_link)) { ! 542: strcpy(cp, " ..."); ! 543: cp += 4; ! 544: } ! 545: break; ! 546: } ! 547: } ! 548: else { ! 549: rp = noderepr(n); ! 550: nch = nchildren(n); ! 551: for (i = 0; i <= nch; ++i) { ! 552: if (i > 0) { ! 553: if (Type(child(n, i)) == Tex) { ! 554: len = Length((value)child(n, i)); ! 555: if (len > 80) ! 556: len = 80; ! 557: strncpy(cp, Str((value)child(n, i)), len); ! 558: cp += len; ! 559: } ! 560: else { ! 561: strcpy(cp, "..."); ! 562: cp += 3; ! 563: } ! 564: } ! 565: if (Fw_negative(rp[i])) { ! 566: strcpy(cp, " ..."); ! 567: cp += 4; ! 568: break; ! 569: } ! 570: if (Fw_positive(rp[i])) { ! 571: strcpy(cp, rp[i]); ! 572: while (*cp) ! 573: ++cp; ! 574: if (cp[-1] == '\t' || cp[-1] == '\b') ! 575: --cp; ! 576: } ! 577: } ! 578: } ! 579: if (cp >= buf+80) { ! 580: strcpy(buf+76, "..."); ! 581: break; ! 582: } ! 583: } ! 584: *cp = 0; ! 585: return buf; ! 586: } ! 587: ! 588: #endif SHOWBUF
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.