home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 198_01 / buffer.c < prev    next >
C/C++ Source or Header  |  1990-01-23  |  19KB  |  624 lines

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