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

Defined functions

addstringtoqueue defined in line 111; used 1 times
addtoqueue defined in line 76; used 6 times
issuggestion defined in line 271; used 3 times
joinqueues defined in line 26; used 3 times
preptoqueue defined in line 47; used 12 times
querepr defined in line 517; used 2 times
resttoqueue defined in line 193; used 4 times
spacefix defined in line 464; used 1 times
splitnode defined in line 149; used 3 times
subsettoqueue defined in line 494; used 4 times

Defined variables

rcsid defined in line 2; never used
Last modified: 1985-08-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3786
Valid CSS Valid XHTML 1.0 Strict