home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / cell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  7.2 KB  |  330 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: cell.c,v 2.4 85/02/12 11:18:00 timo Exp $";
  3.  
  4. /*
  5.  * B editor -- Screen management package, cell list manipulation routines.
  6.  */
  7.  
  8. #include "b.h"
  9. #include "bobj.h"
  10. #include "node.h"
  11. #include "eval.h"
  12. #include "cell.h"
  13.  
  14.  
  15. extern bool dflag;
  16. extern bool noscroll;
  17.  
  18. /*
  19.  * Definitions for internals of cell manipulations.
  20.  */
  21.  
  22. Hidden cell *freelist;
  23.  
  24. #define CELLSIZE (sizeof(cell))
  25.  
  26. #ifndef PAGESIZE /* 4.2 BSD freaks compile with -DPAGESIZE='getpagesize()' */
  27. #define PAGESIZE 1024
  28. #endif
  29.  
  30. #ifndef MALLOCLOSS
  31. #define MALLOCLOSS (sizeof(char*))
  32.     /* number of bytes taken by malloc administration per block */
  33. #endif
  34.  
  35.  
  36. /*
  37.  * Replace `oldlcnt' cells from `tops', starting at the one numbered `oldlno',
  38.  * by the list `rep'.
  39.  * Returns a pointer to the deleted chain (with a Nil end pointer).
  40.  */
  41.  
  42. Visible cell *
  43. replist(tops, rep, oldlno, oldlcnt)
  44.     cell *tops;
  45.     cell *rep;
  46.     int oldlno;
  47.     register int oldlcnt;
  48. {
  49.     cell head;
  50.     register cell *p;
  51.     register cell *q;
  52.     register cell *old;
  53.     register cell *end;
  54.     register int diff;
  55.     int i;
  56.     int replcnt;
  57.  
  58.     if (!tops) /* Start with empty list */
  59.         return rep;
  60.     head.c_link = tops;
  61.     p = &head;
  62.     for (diff = oldlno; diff > 0; --diff) {
  63.         p = p->c_link;
  64.         Assert(p);
  65.     }
  66.     q = p;
  67.     for (i = oldlcnt; i > 0 && p; --i)
  68.         p = p->c_link;
  69.     if (i > 0) {
  70. #ifndef NDEBUG
  71.         debug("[replist jackpot]");
  72. #endif NDEBUG
  73.         oldlcnt -= i;
  74.     }
  75.     old = q->c_link;
  76.     q->c_link = rep;
  77.     if (p) {
  78.         end = p->c_link;
  79.         p->c_link = Cnil;
  80.     }
  81.     for (replcnt = 0; q->c_link; ++replcnt, q = q->c_link)
  82.         ;
  83.     dupmatch(old, rep, oldlcnt, replcnt);
  84.     discard(old);
  85.     if (p)
  86.         q->c_link = end;
  87.     return head.c_link;
  88. }
  89.  
  90.  
  91. /*
  92.  * Allocate a new cell.
  93.  */
  94.  
  95. Hidden cell *
  96. newcell()
  97. {
  98.     register cell *p;
  99.  
  100.     if (!freelist)
  101.         feedfreelist();
  102.     p = freelist;
  103.     freelist = p->c_link;
  104.     p->c_link = Cnil;
  105.     return p;
  106. }
  107.  
  108.  
  109. /*
  110.  * Feed the free list with a block of new entries.
  111.  * We try to keep them together on a page
  112.  * to keep consecutive accesses fast.
  113.  */
  114.  
  115. Hidden Procedure
  116. feedfreelist()
  117. {
  118.     register int n = (PAGESIZE-MALLOCLOSS) / CELLSIZE;
  119.     register cell *p = (cell*) malloc((unsigned)(n*CELLSIZE));
  120.  
  121.     Assert(n > 0);
  122.     if (!p)
  123.         syserr("feedfreelist: malloc");
  124.     freelist = p;
  125.     for (; n > 1; --n, ++p)
  126.         p->c_link = p+1;
  127.     p->c_link = Cnil;
  128. }
  129.  
  130.  
  131. /*
  132.  * Discard all entries of a list of cells.
  133.  */
  134.  
  135. Visible Procedure
  136. discard(p)
  137.     register cell *p;
  138. {
  139.     register cell *savefreelist;
  140.  
  141.     if (!p)
  142.         return;
  143.     savefreelist = p;
  144.     for (;;) {
  145.         noderelease(p->c_data);
  146.         p->c_data = Nnil;
  147.         if (!p->c_link)
  148.             break;
  149.         p = p->c_link;
  150.     }
  151.     p->c_link = freelist;
  152.     freelist = savefreelist;
  153. }
  154.  
  155.  
  156. /*
  157.  * Replace the `onscreen' fields in the replacement chain by those
  158.  * in the old chain, if they match.
  159.  */
  160.  
  161. Hidden Procedure
  162. dupmatch(old, rep, oldcnt, repcnt)
  163.     register cell *old;
  164.     register cell *rep;
  165.     int oldcnt;
  166.     int repcnt;
  167. {
  168.     register int diff = repcnt - oldcnt;
  169.  
  170. #ifndef NDEBUG
  171.     if (dflag)
  172.         debug("[dupmatch(oldcnt=%d, newcnt=%d)]", oldcnt, repcnt);
  173. #endif NDEBUG
  174.     while (rep && old) {
  175.         if (old->c_length == rep->c_length
  176.             && eqlines(old->c_data, rep->c_data)) {
  177.             if (old->c_onscreen != Nowhere) {
  178.                 rep->c_onscreen = old->c_onscreen;
  179.                 rep->c_oldindent = old->c_oldindent;
  180.                 rep->c_oldvhole = old->c_oldvhole;
  181.                 rep->c_oldfocus = old->c_oldfocus;
  182.             }
  183.             rep = rep->c_link;
  184.             old = old->c_link;
  185.         }
  186.         else {
  187.             if (diff >= 0) {
  188.                 --diff;
  189.                 rep = rep->c_link;
  190.             }
  191.             if (diff < 0) {
  192.                 ++diff;
  193.                 old = old->c_link;
  194.             }
  195.         }
  196.     }
  197. }
  198.  
  199.  
  200. /*
  201.  * Build a list of cells consisting of the first `lcnt' lines of the tree.
  202.  */
  203.  
  204. Visible cell *
  205. build(p, lcnt)
  206.     /*auto*/ path p;
  207.     register int lcnt;
  208. {
  209.     cell head;
  210.     register cell *q = &head;
  211.  
  212.     p = pathcopy(p);
  213.     for (;;) {
  214.         q = q->c_link = newcell();
  215.         q->c_onscreen = Nowhere;
  216.         q->c_data = nodecopy(tree(p));
  217.         q->c_length = linelen(q->c_data);
  218.         q->c_newindent = Level(p) * TABS;
  219.         q->c_oldindent = 0;
  220.         q->c_oldvhole = q->c_newvhole = q->c_oldfocus = q->c_newfocus = No;
  221.         --lcnt;
  222.         if (lcnt <= 0)
  223.             break;
  224.         nextline(&p) || Abort();
  225.     }
  226.     q->c_link = Cnil;
  227.     pathrelease(p);
  228.     return head.c_link;
  229. }
  230.  
  231.  
  232. /*
  233.  * Decide which line is to be on top of the screen.
  234.  * We slide a window through the list of lines, recognizing
  235.  * lines of the focus and lines already on the screen,
  236.  * and stop as soon as we find a reasonable focus position.
  237.  *
  238.  * - The focus must always be on the screen completely;
  239.  *   if it is larger than the screen, its first line must be
  240.  *   on top of the screen.
  241.  * - When old lines can be retained, at least one line above
  242.  *   and below the focus must be shown; the retained lines
  243.  *   should be moved as little as possible.
  244.  * - As little as possible blank space should be shown at the
  245.  *   bottom, even if the focus is at the end of the unit.
  246.  * - If no rule applies, try to center the focus on the screen.
  247.  * - If noscroll is Yes (the terminal can't scroll), and the top
  248.  *   line can't be retained, also try to center the focus on the
  249.  *   screen.
  250.  */
  251.  
  252. Visible cell *
  253. gettop(tops)
  254.     cell *tops;
  255. {
  256.     register cell *pfwa = tops; /* First line of sliding window */
  257.     register cell *plwa = tops; /* Last+1 line of sliding window */
  258.     register cell *pffocus = Cnil; /* First line of focus */
  259.     cell *pscreen = Cnil; /* First line still on screen */
  260.     register int nfwa = 0; /* Corresponding line numbers in parse tree */
  261.     register int nlwa = 0;
  262.     register int nffocus;
  263.     int nlfocus;
  264.     int nscreen;
  265.     int size;
  266.  
  267.     for (;;) { /* plwa is the current candidate for top line. */
  268.         if (!pfwa) {
  269. #ifndef NDEBUG
  270.             debug("[Lost the focus!]");
  271. #endif NDEBUG
  272.             return tops; /* To show *something*... */
  273.         }
  274.         while (plwa && nlwa < nfwa+winheight) {
  275.             /* Find first line *not* in window */
  276.             size = Space(plwa);
  277.             if (plwa->c_newfocus) { /* Hit a focus line */
  278.                 if (!pffocus) { /* Note first focus line */
  279.                     pffocus = plwa;
  280.                     nffocus = nlwa;
  281.                 }
  282.                 nlfocus = nlwa + size;
  283.             }
  284.             if (plwa->c_onscreen != Nowhere) { /* Hello old chap */
  285.                 if (!pscreen) { /* Note first line on screen */
  286.                     pscreen = plwa;
  287.                     nscreen = nlwa;
  288.                 }
  289.             }
  290.             nlwa += size;
  291.             plwa = plwa->c_link;
  292.         }
  293.         if (pffocus) {
  294.             /* Focus in sight; stop at first reasonable opportunity */
  295.             if (pffocus == pfwa)
  296.                 break; /* Grab last chance! */
  297.             if (!noscroll && nlwa - nfwa <= winheight - winheight/3)
  298.                 break; /* Don't show too much white space at bottom */
  299.             if (pffocus == pfwa->c_link && nlfocus < nfwa+winheight)
  300.                 break; /* Near top line */
  301.             if (pscreen && (!noscroll || nffocus > nscreen)) {
  302.                 /* Conservatism may succeed */
  303.                 if (pscreen->c_onscreen >= nscreen - nfwa
  304.                     && (nlfocus < nfwa+winheight
  305.                         || !plwa && nlfocus == nfwa+winheight))
  306.                     break; /* focus entirely on screen */
  307.             }
  308.             else { /* No comrades seen */
  309.                 if (nffocus - nfwa <= nfwa+winheight - nlfocus
  310.                     || !plwa && nlwa <= nfwa+winheight)
  311.                     break; /* Nicely centered focus or end of unit */
  312.             }
  313.         }
  314.         if (pfwa == pscreen) { /* Say farewell to oldest comrade */
  315.             pscreen->c_onscreen = Nowhere;
  316.             do { /* Find next in age */
  317.                 nscreen += Space(pscreen);
  318.                 pscreen = pscreen->c_link;
  319.                 if (pscreen == plwa) {
  320.                     pscreen = Cnil;
  321.                     break;
  322.                 }
  323.             } while (pscreen->c_onscreen == Nowhere);
  324.         }
  325.         nfwa += Space(pfwa);
  326.         pfwa = pfwa->c_link; /* Pass the buck */
  327.     }
  328.     return pfwa; /* This is what all those breaks aim at */
  329. }
  330.