home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / memacs400_src.lzh / MEMACS400 / SRC / buffer.c < prev    next >
Text File  |  1996-04-25  |  16KB  |  673 lines

  1. /*  BUFFER.C:    buffer mgmt. routines
  2.         MicroEMACS 4.00
  3.  
  4.  * Buffer management.
  5.  * Some of the functions are internal,
  6.  * and some are actually attached to user
  7.  * keys. Like everyone else, they set hints
  8.  * for the display system.
  9.  */
  10. #include    <stdio.h>
  11. #include    "estruct.h"
  12. #include    "eproto.h"
  13. #include    "edef.h"
  14. #include    "elang.h"
  15.  
  16. /*
  17.  * Attach a buffer to a window. The
  18.  * values of dot and mark come from the buffer
  19.  * if the use count is 0. Otherwise, they come
  20.  * from some other window.
  21.  */
  22. PASCAL NEAR usebuffer(f, n)
  23.  
  24. int f,n;    /* prefix flag and argument */
  25.  
  26. {
  27.     register BUFFER *bp;    /* temporary buffer pointer */
  28.  
  29.     /* get the buffer name to switch to */
  30.     bp = getdefb();
  31.     bp = getcbuf(TEXT24, bp ? bp->b_bname : mainbuf, TRUE);
  32. /*                "Use buffer" */
  33.     if (!bp)
  34.         return(ABORT);
  35.  
  36.     /* make it invisible if there is an argument */
  37.     if (f == TRUE)
  38.         bp->b_flag |= BFINVS;
  39.  
  40.     /* switch to it in any case */
  41.     return(swbuffer(bp));
  42. }
  43.  
  44. PASCAL NEAR nextbuffer(f, n)    /* switch to the next buffer in the buffer list */
  45.  
  46. int f, n;    /* default flag, numeric argument */
  47. {
  48.     register BUFFER *bp;    /* current eligable buffer */
  49.     register int status;
  50.  
  51.     /* make sure the arg is legit */
  52.     if (f == FALSE)
  53.         n = 1;
  54.     if (n < 1)
  55.         return(FALSE);
  56.  
  57.     /* cycle thru buffers until n runs out */
  58.     while (n-- > 0) {
  59.         bp = getdefb();
  60.         if (bp == NULL)
  61.             return(FALSE);
  62.         status = swbuffer(bp);
  63.         if (status != TRUE)
  64.             return(status);
  65.     }
  66.     return(status);
  67. }
  68.  
  69. PASCAL NEAR swbuffer(bp)    /* make buffer BP current */
  70.  
  71. BUFFER *bp;
  72.  
  73. {
  74.     register EWINDOW *wp;
  75.     SCREEN *scrp;        /* screen to fix pointers in */
  76.     register int cmark;        /* current mark */
  77.  
  78.     /* let a user macro get hold of things...if he wants */
  79.     execkey(&exbhook, FALSE, 1);
  80.  
  81.     /* unuse the current buffer, saving window info to buffer struct */
  82.     if (--curbp->b_nwnd == 0) {        /* Last use.        */
  83.         curbp->b_dotp  = curwp->w_dotp;
  84.         curbp->b_doto  = curwp->w_doto;
  85.         for (cmark = 0; cmark < NMARKS; cmark++) {
  86.             curbp->b_markp[cmark] = curwp->w_markp[cmark];
  87.             curbp->b_marko[cmark] = curwp->w_marko[cmark];
  88.         }
  89.         curbp->b_fcol  = curwp->w_fcol;
  90.     }
  91.  
  92.     /* let time march forward! */
  93.     access_time++;
  94.  
  95.     curbp = bp;                /* Switch.        */
  96.     bp->last_access = access_time;
  97.     if (curbp->b_active != TRUE) {        /* buffer not active yet*/
  98.         /* read it in and activate it */
  99.         readin(curbp->b_fname, ((curbp->b_mode&MDVIEW) == 0));
  100.         curbp->b_dotp = lforw(curbp->b_linep);
  101.         curbp->b_doto = 0;
  102.         curbp->b_active = TRUE;
  103.     }
  104.     curwp->w_bufp  = bp;
  105.     curwp->w_linep = bp->b_linep;        /* For macros, ignored. */
  106.     curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.     */
  107.     if (bp->b_nwnd++ == 0) {        /* First use.        */
  108.         curwp->w_dotp  = bp->b_dotp;
  109.         curwp->w_doto  = bp->b_doto;
  110.         for (cmark = 0; cmark < NMARKS; cmark++) {
  111.             curwp->w_markp[cmark] = bp->b_markp[cmark];
  112.             curwp->w_marko[cmark] = bp->b_marko[cmark];
  113.         }
  114.         curwp->w_fcol  = bp->b_fcol;
  115.     } else {
  116.         /* in all screens.... */
  117.         scrp = first_screen;
  118.         while (scrp) {
  119.             wp = scrp->s_first_window;
  120.             while (wp != NULL) {
  121.                 if (wp!=curwp && wp->w_bufp==bp) {
  122.                     curwp->w_dotp  = wp->w_dotp;
  123.                     curwp->w_doto  = wp->w_doto;
  124.                     for (cmark = 0; cmark < NMARKS; cmark++) {
  125.                         curwp->w_markp[cmark] = wp->w_markp[cmark];
  126.                         curwp->w_marko[cmark] = wp->w_marko[cmark];
  127.                     }
  128.                     curwp->w_fcol  = wp->w_fcol;
  129.                     break;
  130.                 }
  131.                 /* next window */
  132.                 wp = wp->w_wndp;
  133.             }
  134.  
  135.             /* next screen! */
  136.             scrp = scrp->s_next_screen;
  137.         }
  138.     }
  139.  
  140.     /* let a user macro get hold of things...if he wants */
  141.     execkey(&bufhook, FALSE, 1);
  142.  
  143.     return(TRUE);
  144. }
  145.  
  146. /*
  147.  * Dispose of a buffer, by name.
  148.  * Ask for the name. Look it up (don't get too
  149.  * upset if it isn't there at all!). Get quite upset
  150.  * if the buffer is being displayed. Clear the buffer (ask
  151.  * if the buffer has been changed). Then free the header
  152.  * line and the buffer header. Bound to "C-X K".
  153.  */
  154. PASCAL NEAR killbuffer(f, n)
  155.  
  156. int f,n;    /* prefix flag and argument */
  157.  
  158. {
  159.     register BUFFER *bp;    /* ptr to buffer to dump */
  160.  
  161.     /* get the buffer name to kill */
  162.     bp = getdefb();
  163.     bp = getcbuf(TEXT26, bp ? bp->b_bname : mainbuf, TRUE);
  164. /*             "Kill buffer" */
  165.     if (bp == NULL)
  166.         return(ABORT);
  167.  
  168.     return(zotbuf(bp));
  169. }
  170.  
  171. /*    Allow the user to pop up a buffer, like we do.... */
  172.  
  173. PASCAL NEAR popbuffer(f, n)
  174.  
  175. int f, n;    /* default and numeric arguments */
  176.  
  177. {
  178.     register BUFFER *bp;    /* ptr to buffer to dump */
  179.  
  180.     /* get the buffer name to pop */
  181.     bp = getdefb();
  182.     bp = getcbuf(TEXT27, bp ? bp->b_bname : mainbuf, TRUE);
  183. /*             "Pop buffer" */
  184.     if (bp == NULL)
  185.         return(ABORT);
  186.  
  187.     /* make it invisible if there is an argument */
  188.     if (f == TRUE)
  189.         bp->b_flag |= BFINVS;
  190.  
  191.     return(pop(bp));
  192. }
  193.  
  194. BUFFER *PASCAL NEAR getdefb()    /* get the default buffer for a use or kill */
  195.  
  196. {
  197.     BUFFER *bp;    /* default buffer */
  198.  
  199.     /* Find the next buffer, which will be the default */
  200.     bp = curbp->b_bufp;
  201.  
  202.     /* cycle through the buffers to find an eligable one */
  203.     while (bp == NULL || bp->b_flag & BFINVS) {
  204.         if (bp == NULL)
  205.             bp = bheadp;
  206.         else
  207.             bp = bp->b_bufp;
  208.  
  209.         /* don't get caught in an infinite loop! */
  210.         if (bp == curbp) {
  211.             bp = NULL;
  212.             break;
  213.         }
  214.     }            
  215.     return(bp);
  216. }
  217.  
  218. PASCAL NEAR zotbuf(bp)    /* kill the buffer pointed to by bp */
  219.  
  220. register BUFFER *bp;
  221.  
  222. {
  223.     register BUFFER *bp1;
  224.     register BUFFER *bp2;
  225.     register int result;
  226.     register PARG *tmp_arg;
  227.  
  228.     /* we can not kill a displayed buffer */
  229.     if (bp->b_nwnd != 0) {
  230.         mlwrite(TEXT28);
  231. /*            "Buffer is being displayed" */
  232.         return(FALSE);
  233.     }
  234.  
  235.     /* we can not kill an executing buffer */
  236.     if (bp->b_exec != 0) {
  237.         mlwrite(TEXT226);
  238. /*            "%%Can not delete an executing buffer" */
  239.         return(FALSE);
  240.     }
  241.  
  242.     /* dump any arguments */
  243.     while (bp->b_args) {
  244.         tmp_arg = bp->b_args;
  245.         bp->b_args = bp->b_args->next;
  246.         free(tmp_arg);
  247.     }
  248.  
  249.     /* if anything is bound to the buffer,
  250.        unbind them */
  251.     unbind_buf(bp);
  252.  
  253.     /* dump it's undo stack */
  254.     undo_zot(bp);
  255.  
  256.     if ((result = bclear(bp)) != TRUE)    /* Blow text away.    */
  257.         return(result);
  258.     free((char *) bp->b_linep);        /* Release header line. */
  259.     bp1 = NULL;                /* Find the header.    */
  260.     bp2 = bheadp;
  261.     while (bp2 != bp) {
  262.         bp1 = bp2;
  263.         bp2 = bp2->b_bufp;
  264.     }
  265.     bp2 = bp2->b_bufp;            /* Next one in chain.    */
  266.     if (bp1 == NULL)            /* Unlink it.        */
  267.         bheadp = bp2;
  268.     else
  269.         bp1->b_bufp = bp2;
  270.     free((char *) bp);            /* Release buffer block */
  271.     return(TRUE);
  272. }
  273.  
  274. PASCAL NEAR namebuffer(f,n)    /*    Rename the current buffer    */
  275.  
  276. int f, n;        /* default Flag & Numeric arg */
  277.  
  278. {
  279.     register BUFFER *bp;    /* pointer to scan through all buffers */
  280.     char bufn[NBUFN];    /* buffer to hold buffer name */
  281.  
  282.     /* prompt for and get the new buffer name */
  283. ask:    if (mlreply(TEXT29, bufn, NBUFN) != TRUE)
  284. /*            "Change buffer name to: " */
  285.         return(FALSE);
  286.  
  287.     /* and check for duplicates */
  288.     bp = bheadp;
  289.     while (bp != NULL) {
  290.         if (bp != curbp) {
  291.             /* if the names the same */
  292.             if (strcmp(bufn, bp->b_bname) == 0)
  293.                 goto ask;  /* try again */
  294.         }
  295.         bp = bp->b_bufp;    /* onward */
  296.     }
  297.  
  298.     strcpy(curbp->b_bname, bufn);    /* copy buffer name to structure */
  299.     upmode();            /* make all mode lines replot */
  300.     mlerase();
  301.     return(TRUE);
  302. }
  303.  
  304. /*    Build and popup a buffer containing the list of all buffers.
  305.     Bound to "C-X C-B". A numeric argument forces it to list
  306.     invisible buffers as well.
  307. */
  308.  
  309. PASCAL NEAR listbuffers(f, n)
  310.  
  311. int f,n;    /* prefix flag and argument */
  312.  
  313. {
  314.     register int status;    /* stutus return */
  315.  
  316.     if ((status = makelist(f)) != TRUE)
  317.         return(status);
  318.     return(wpopup(blistp));
  319. }
  320.  
  321. /*
  322.  * This routine rebuilds the
  323.  * text in the special secret buffer
  324.  * that holds the buffer list. It is called
  325.  * by the list buffers command. Return TRUE
  326.  * if everything works. Return FALSE if there
  327.  * is an error (if there is no memory). Iflag
  328.  * indicates whether to list hidden buffers.
  329.  */
  330. PASCAL NEAR makelist(iflag)
  331.  
  332. int iflag;    /* list hidden buffer flag */
  333.  
  334. {
  335.     register char    *cp1;
  336.     register char    *cp2;
  337.     register BUFFER *bp;
  338.     register LINE    *lp;
  339.     register int    s;
  340.     register int    i;
  341.     long nbytes;        /* # of bytes in current buffer */
  342.     char b[7+1];
  343.     char line[128];
  344.  
  345.     blistp->b_flag &= ~BFCHG;        /* Don't complain!    */
  346.     if ((s=bclear(blistp)) != TRUE)     /* Blow old text away    */
  347.         return(s);
  348.     strcpy(blistp->b_fname, "");
  349.     if (addline(blistp, TEXT30) == FALSE
  350. /*            "ACTN   Modes        Size Buffer       File" */
  351.     ||  addline(blistp, "---- ----------- ------- --------------- ----") == FALSE)
  352.         return(FALSE);
  353.     bp = bheadp;                /* For all buffers    */
  354.  
  355.     /* build line to report global mode settings */
  356.     cp1 = &line[0];
  357.     *cp1++ = ' ';
  358.     *cp1++ = ' ';
  359.     *cp1++ = ' ';
  360.     *cp1++ = ' ';
  361.     *cp1++ = ' ';
  362.  
  363.     /* output the mode codes */
  364.     for (i = 0; i < NUMMODES; i++)
  365.         if (gmode & (1 << i))
  366.             *cp1++ = modecode[i];
  367.         else
  368.             *cp1++ = '.';
  369.     strcpy(cp1, TEXT31);
  370. /*            "          Global Modes" */
  371.     if (addline(blistp, line) == FALSE)
  372.         return(FALSE);
  373.  
  374.     /* output the list of buffers */
  375.     while (bp != NULL) {
  376.         /* skip invisible buffers if iflag is false */
  377.         if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
  378.             bp = bp->b_bufp;
  379.             continue;
  380.         }
  381.         cp1 = &line[0];         /* Start at left edge    */
  382.  
  383.         /* output status of ACTIVE flag (has the file been read in? */
  384.         if (bp->b_active == TRUE)    /* "@" if activated       */
  385.             *cp1++ = '@';
  386.         else
  387.             *cp1++ = ' ';
  388.  
  389.         /* output status of changed flag */
  390.         if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed    */
  391.             *cp1++ = '*';
  392.         else
  393.             *cp1++ = ' ';
  394.  
  395.         /* report if the file is truncated */
  396.         if ((bp->b_flag&BFTRUNC) != 0)
  397.             *cp1++ = '#';
  398.         else
  399.             *cp1++ = ' ';
  400.  
  401.         /* report if the file is narrowed */
  402.         if ((bp->b_flag&BFNAROW) != 0)
  403.             *cp1++ = '<';
  404.         else
  405.             *cp1++ = ' ';
  406.  
  407.         *cp1++ = ' ';    /* space */
  408.  
  409.         /* output the mode codes */
  410.         for (i = 0; i < NUMMODES; i++) {
  411.             if (bp->b_mode & (1 << i))
  412.                 *cp1++ = modecode[i];
  413.             else
  414.                 *cp1++ = '.';
  415.         }
  416.         *cp1++ = ' ';            /* Gap.         */
  417.         nbytes = 0L;            /* Count bytes in buf.    */
  418.         lp = lforw(bp->b_linep);
  419.         while (lp != bp->b_linep) {
  420.             nbytes += (long)lused(lp)+1L;
  421.             lp = lforw(lp);
  422.         }
  423.         flong_asc(b, 7, nbytes);         /* 7 digit buffer size. */
  424.         cp2 = &b[0];
  425.         while (*cp2)
  426.             *cp1++ = *cp2++;
  427.         *cp1++ = ' ';            /* Gap.         */
  428.         cp2 = &bp->b_bname[0];        /* Buffer name        */
  429.         while (*cp2)
  430.             *cp1++ = *cp2++;
  431.         *cp1++ = ' ';            /* Gap.         */
  432.         cp2 = &bp->b_fname[0];        /* File name        */
  433.         if (*cp2 != 0) {
  434.             while (cp1 < &line[41])
  435.                 *cp1++ = ' ';
  436.             while (*cp2)
  437.                 *cp1++ = *cp2++;
  438.         }
  439.  
  440.         if (dispundo) {
  441.             while (cp1 - line < 50)
  442.                 *cp1++ = ' ';
  443.             flong_asc(b, 5, bp->last_access);
  444.             cp2 = &b[0];
  445.             while (*cp2)
  446.                 *cp1++ = *cp2++;
  447.             flong_asc(b, 7, bp->undo_count);
  448.             cp2 = &b[0];
  449.             while (*cp2)
  450.                 *cp1++ = *cp2++;
  451.         }
  452.  
  453.         *cp1 = 0;          /* Add to the buffer.   */
  454.         if (addline(blistp, line) == FALSE)
  455.             return(FALSE);
  456.         bp = bp->b_bufp;
  457.     }
  458.     return(TRUE);                   /* All done           */
  459. }
  460.  
  461. /* Translate a long to ascii form. Don't trust various systems
  462.    ltoa() routines.. they aren't consistant                */
  463.  
  464. VOID PASCAL NEAR flong_asc(buf, width, num)
  465.  
  466. char   buf[];
  467. int    width;
  468. long   num;
  469.  
  470. {
  471.     buf[width] = 0;             /* End of string.    */
  472.     while (num >= 10) {            /* Conditional digits.    */
  473.         buf[--width] = (int)(num%10L) + '0';
  474.         num /= 10L;
  475.     }
  476.     buf[--width] = (int)num + '0';        /* Always 1 digit.    */
  477.     while (width != 0)            /* Pad with blanks.    */
  478.         buf[--width] = ' ';
  479. }
  480.  
  481. /*
  482.  * Look through the list of
  483.  * buffers. Return TRUE if there
  484.  * are any changed buffers. Buffers
  485.  * that hold magic internal stuff are
  486.  * not considered; who cares if the
  487.  * list of buffer names is hacked.
  488.  * Return FALSE if no buffers
  489.  * have been changed.
  490.  */
  491. PASCAL NEAR anycb()
  492. {
  493.     register BUFFER *bp;
  494.  
  495.     bp = bheadp;
  496.     while (bp != NULL) {
  497.         if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
  498.             return(TRUE);
  499.         bp = bp->b_bufp;
  500.     }
  501.     return(FALSE);
  502. }
  503.  
  504. /*
  505.  * Find a buffer, by name. Return a pointer
  506.  * to the BUFFER structure associated with it.
  507.  * If the buffer is not found
  508.  * and the "cflag" is TRUE, create it. The "bflag" is
  509.  * the settings for the flags in in buffer.
  510.  */
  511. BUFFER *PASCAL NEAR bfind(bname, cflag, bflag)
  512.  
  513. register char    *bname; /* name of buffer to find */
  514. int cflag;        /* create it if not found? */
  515. int bflag;        /* bit settings for a new buffer */
  516.  
  517. {
  518.     register BUFFER *bp;
  519.     register BUFFER *sb;    /* buffer to insert after */
  520.     register LINE    *lp;
  521.     int cmark;        /* current mark */
  522.  
  523.     bp = bheadp;
  524.     while (bp != NULL) {
  525.         if (strcmp(bname, bp->b_bname) == 0)
  526.             return(bp);
  527.         bp = bp->b_bufp;
  528.     }
  529.  
  530.     /* no such buffer exists, create it? */
  531.     if (cflag != FALSE) {
  532.  
  533.         /* allocate the needed memory */
  534.         if ((bp=(BUFFER *)room(sizeof(BUFFER))) == NULL)
  535.             return(NULL);
  536.         if ((lp=lalloc(0)) == NULL) {
  537.             free((char *) bp);
  538.             return(NULL);
  539.         }
  540.  
  541.         /* find the place in the list to insert this buffer */
  542.         if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
  543.             /* insert at the beginning */
  544.             bp->b_bufp = bheadp;
  545.             bheadp = bp;
  546.         } else {
  547.             sb = bheadp;
  548.             while (sb->b_bufp != NULL) {
  549.                 if (strcmp(sb->b_bufp->b_bname, bname) > 0)
  550.                     break;
  551.                 sb = sb->b_bufp;
  552.             }
  553.  
  554.             /* and insert it */
  555.             bp->b_bufp = sb->b_bufp;
  556.             sb->b_bufp = bp;
  557.         }
  558.  
  559.         /* and set up the other buffer fields */
  560.         bp->b_topline = NULL;
  561.         bp->b_botline = NULL;
  562.         bp->undo_head = (UNDO_OBJ *)NULL;
  563.         bp->undo_count = 0L;
  564.         bp->last_access = access_time;
  565.         bp->b_active = TRUE;
  566.         bp->b_dotp  = lp;
  567.         bp->b_doto  = 0;
  568.         for (cmark = 0; cmark < NMARKS; cmark++) {
  569.             bp->b_markp[cmark] = NULL;
  570.             bp->b_marko[cmark] = 0;
  571.         }
  572.         bp->b_fcol  = 0;
  573.         bp->b_flag  = bflag;
  574.         bp->b_mode  = gmode;
  575.         bp->b_nwnd  = 0;
  576.         bp->b_exec  = 0;
  577.         bp->b_linep = lp;
  578.         strcpy(bp->b_fname, "");
  579.         strcpy(bp->b_bname, bname);
  580. #if    CRYPT
  581.         bp->b_key[0] = 0;
  582. #endif
  583.         bp->b_numargs = NOTPROC;
  584.         bp->b_args = (PARG *)NULL;
  585.         lp->l_fp = lp;
  586.         lp->l_bp = lp;
  587.     }
  588.     return(bp);
  589. }
  590.  
  591. /*
  592.  * This routine blows away all of the text
  593.  * in a buffer. If the buffer is marked as changed
  594.  * then we ask if it is ok to blow it away; this is
  595.  * to save the user the grief of losing text. The
  596.  * window chain is nearly always wrong if this gets
  597.  * called; the caller must arrange for the updates
  598.  * that are required. Return TRUE if everything
  599.  * looks good.
  600.  */
  601. PASCAL NEAR bclear(bp)
  602. register BUFFER *bp;
  603. {
  604.     register LINE    *lp;
  605.     register int    s;
  606.     int cmark;        /* current mark */
  607.  
  608.     if ((bp->b_flag&BFINVS) == 0        /* Not scratch buffer.    */
  609.     && (bp->b_flag&BFCHG) != 0        /* Something changed    */
  610.     && (s=mlyesno(TEXT32)) != TRUE)
  611. /*              "Discard changes" */
  612.         return(s);
  613.     bp->b_flag  &= ~BFCHG;            /* Not changed        */
  614.     while ((lp=lforw(bp->b_linep)) != bp->b_linep)
  615.         lfree(lp);
  616.     bp->b_dotp  = bp->b_linep;        /* Fix "."        */
  617.     bp->b_doto  = 0;
  618.     for (cmark = 0; cmark < NMARKS; cmark++) {
  619.         bp->b_markp[cmark] = NULL;  /* Invalidate "mark"    */
  620.         bp->b_marko[cmark] = 0;
  621.     }
  622.     bp->b_fcol = 0;
  623.     undo_zot(bp);    /* discard undo info for this buffer! */
  624.     return(TRUE);
  625. }
  626.  
  627. PASCAL NEAR unmark(f, n)    /* unmark the current buffers change flag */
  628.  
  629. int f, n;    /* unused command arguments */
  630.  
  631. {
  632.     /* unmark the buffer */
  633.     curbp->b_flag &= ~BFCHG;
  634.  
  635.     /* unmark all windows as well */
  636.     upmode();
  637.  
  638.     return(TRUE);
  639. }
  640.  
  641. BUFFER *PASCAL NEAR getoldb()    /* get the most ancient visited buffer */
  642.  
  643. {
  644.     BUFFER *bp;    /* current buffer */
  645.     BUFFER *old_bp;    /* ptr to oldest buffer */
  646.     long old_count;    /* oldest count */
  647.  
  648.     /* Find the next buffer, which will be the default */
  649.     bp = bheadp;
  650.     old_bp = (BUFFER *)NULL;
  651.     old_count = 0;
  652.  
  653.     /* Scan the buffer list */
  654.     while (bp) {
  655.  
  656.         /* if this one is older..... */
  657.         if ((bp->last_access > 0L) &&
  658.             ((old_bp == (BUFFER *)NULL) ||
  659.              (bp->last_access < old_count))) {
  660.  
  661.             /* record this as the oldest buffer */
  662.             old_bp = bp;
  663.             old_count = bp->last_access;
  664.         }
  665.  
  666.         /* on to the next buffer in the list */
  667.         bp = bp->b_bufp;
  668.     }
  669.  
  670.     return(old_bp);
  671. }
  672.  
  673.