home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / buffer.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  23KB  |  993 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.  * $Log: buffer.c,v $
  9.  * Revision 1.42  1992/12/02  09:13:16  foxharp
  10.  * changes for "c-shiftwidth"
  11.  *
  12.  * Revision 1.41  1992/11/19  08:48:14  foxharp
  13.  * took out restriction against killing invisible buffers
  14.  *
  15.  * Revision 1.40  1992/08/20  23:40:48  foxharp
  16.  * typo fixes -- thanks, eric
  17.  *
  18.  * Revision 1.39  1992/08/05  21:52:33  foxharp
  19.  * print filenames with DOS drive designators correctly
  20.  *
  21.  * Revision 1.38  1992/07/30  07:28:53  foxharp
  22.  * don't prepend "./" to non-files in buffer list
  23.  *
  24.  * Revision 1.37  1992/07/24  07:49:38  foxharp
  25.  * shorten_name changes
  26.  *
  27.  * Revision 1.36  1992/07/18  13:13:56  foxharp
  28.  * put all path-shortening in one place (shorten_path()), and took out some old code now
  29.  * unnecessary
  30.  *
  31.  * Revision 1.35  1992/07/15  08:52:44  foxharp
  32.  * trim leading `pwd` from buffer names in buffer list
  33.  *
  34.  * Revision 1.34  1992/07/13  19:36:13  foxharp
  35.  * show current directory in buffer list
  36.  *
  37.  * Revision 1.33  1992/05/16  12:00:31  pgf
  38.  * prototypes/ansi/void-int stuff/microsoftC
  39.  *
  40.  * Revision 1.32  1992/03/05  09:19:55  pgf
  41.  * changed some mlwrite() to mlforce(), due to new terse support
  42.  *
  43.  * Revision 1.31  1992/01/05  00:06:13  pgf
  44.  * split mlwrite into mlwrite/mlprompt/mlforce to make errors visible more
  45.  * often.  also normalized message appearance somewhat.
  46.  *
  47.  * Revision 1.30  1992/01/03  23:33:50  pgf
  48.  * use new ch_fname() routine to manipulate filenames
  49.  *
  50.  * Revision 1.29  1991/11/12  23:50:10  pgf
  51.  * no longer allocate text for the header line -- the scanner doesn't
  52.  * need it
  53.  *
  54.  * Revision 1.28  1991/11/12  23:43:23  pgf
  55.  * pass stringend param to regexp, for end of string
  56.  *
  57.  * Revision 1.27  1991/11/08  13:08:44  pgf
  58.  * ifdefed unused func
  59.  *
  60.  * Revision 1.26  1991/11/03  17:48:11  pgf
  61.  * pass -1 to regexec to indicate no srchlim specified -- 0 was ambiguous
  62.  *
  63.  * Revision 1.25  1991/11/01  14:38:00  pgf
  64.  * saber cleanup
  65.  *
  66.  * Revision 1.24  1991/10/28  14:21:05  pgf
  67.  * renamed curtabstopval to curtabval, initialized new b_acount field
  68.  * in BUFFER struct
  69.  *
  70.  * Revision 1.23  1991/10/28  01:01:06  pgf
  71.  * added start offset and end offset to regexec calls
  72.  *
  73.  * Revision 1.22  1991/10/26  00:10:35  pgf
  74.  * use regexec for c suffixes
  75.  *
  76.  * Revision 1.21  1991/10/23  14:19:53  pgf
  77.  * allocate some text for a buffer's header line, and put a -1 there as the
  78.  * first and only character.  this helps the search engine.
  79.  *
  80.  * Revision 1.20  1991/10/22  14:08:23  pgf
  81.  * took out old ifdef BEFORE code
  82.  *
  83.  * Revision 1.19  1991/10/10  12:33:33  pgf
  84.  * changes to support "block malloc" of line text -- now for most files
  85.  * there is are two mallocs and a single read, no copies.  previously there
  86.  * were two mallocs per line, and two copies (stdio's and ours).  This change
  87.  * implies that lines and line text should not move between buffers, without
  88.  * checking that the text and line struct do not "belong" to the buffer.
  89.  *
  90.  * Revision 1.18  1991/09/30  01:47:24  pgf
  91.  * don't allow recursive zotbuf() via delwp()
  92.  *
  93.  * Revision 1.17  1991/09/26  13:17:11  pgf
  94.  * can now kill a displayed buffer, and
  95.  * we initialize window values at creation time
  96.  *
  97.  * Revision 1.16  1991/09/20  13:11:53  pgf
  98.  * protect against null curtabstopval after make_current() returns
  99.  *
  100.  * Revision 1.15  1991/09/10  12:30:45  pgf
  101.  * initialize b_wline when creating buffer
  102.  *
  103.  * Revision 1.14  1991/09/10  01:52:05  pgf
  104.  * fixed bug caused by re-tabbing
  105.  *
  106.  * Revision 1.13  1991/09/10  00:50:23  pgf
  107.  * re-tab, and elim. unused local in swbuffer
  108.  *
  109.  * Revision 1.12  1991/08/16  11:03:50    pgf
  110.  * since we now switch to popped up buffers, the numbering in the buffer
  111.  * list was off by one -- now we number from 1
  112.  *
  113.  * Revision 1.11  1991/08/12  09:25:10    pgf
  114.  * now store w_line in w_traits while buffer is offscreen, so reframe
  115.  * isn't always necessary.  don't force reframe on redisplay.
  116.  *
  117.  * Revision 1.10  1991/08/08  13:15:25    pgf
  118.  * removed some ifdef BEFORE
  119.  *
  120.  * Revision 1.9  1991/08/07  12:35:07  pgf
  121.  * added RCS log messages
  122.  *
  123.  * revision 1.8
  124.  * date: 1991/08/06 15:11:31;
  125.  * global/local values
  126.  * and printf/list stuff
  127.  * 
  128.  * revision 1.7
  129.  * date: 1991/06/25 19:52:06;
  130.  * massive data structure restructure
  131.  * 
  132.  * revision 1.6
  133.  * date: 1991/06/16 17:34:23;
  134.  * added support for local values of tabstops and fillcol
  135.  * 
  136.  * revision 1.5
  137.  * date: 1991/04/08 15:45:31;
  138.  * fixed readin() arg count
  139.  * 
  140.  * revision 1.4
  141.  * date: 1991/04/04 09:28:02;
  142.  * line text is now separate from LINE struct
  143.  * 
  144.  * revision 1.3
  145.  * date: 1991/02/21 09:15:35;
  146.  * added horizontal scroll support
  147.  * 
  148.  * revision 1.2
  149.  * date: 1990/12/06 19:47:56;
  150.  * fixed list-buffer window re-use problem, and startup core dumps
  151.  * if popupbuff was called in startup file
  152.  * 
  153.  * revision 1.1
  154.  * date: 1990/09/21 10:24:46;
  155.  * initial vile RCS revision
  156.  */
  157. #include    <stdio.h>
  158. #include    "estruct.h"
  159. #include    "edef.h"
  160.  
  161.  
  162. /* c is either first character of a filename, or an index into buffer list */
  163. char *
  164. hist_lookup(c)
  165. int c;
  166. {
  167.     register BUFFER *bp;
  168.     static char buf[NBUFN];
  169.     buf[0] = '\0';
  170.  
  171.     if (curbp != bheadp)
  172.         mlforce("BUG: hist_lookup: curbp != bheadp");
  173.             
  174.     bp = curbp->b_bufp; /* always skip the current */
  175.     while (bp != NULL) {
  176.         if (!(bp->b_flag & (BFINVS|BFSCRTCH)) && (--c == 0))
  177.             break;
  178.         bp = bp->b_bufp;
  179.     }
  180.     if (bp)
  181.         return bp->b_bname;
  182.     return NULL;
  183. }
  184.  
  185. int
  186. hist_show()
  187. {
  188.     int i;
  189.     char line[NLINE];
  190.     BUFFER *bp;
  191.         
  192.     if (curbp != bheadp)
  193.         mlforce("BUG: hist_show: curbp != bheadp");
  194.         
  195.     strcpy(line,"");
  196.     for (i = 0, bp = curbp->b_bufp; i < 10 && bp != NULL; bp = bp->b_bufp) {
  197.         if (!(bp->b_flag & (BFINVS|BFSCRTCH))) {
  198.             strcat(line, "  %d");
  199.             if (bp->b_flag & BFCHG)
  200.                 strcat(line, "* ");
  201.             else
  202.                 strcat(line, " ");
  203.             strcat(line, bp->b_bname);
  204.             i++;
  205.         }
  206.     }
  207.     if (strcmp(line,"")) {
  208.         mlforce(line,1,2,3,4,5,6,7,8,9,10);
  209.         return TRUE;
  210.     } else {
  211.         return FALSE;
  212.     }
  213. }
  214.  
  215. int
  216. histbuff(f,n)
  217. int f,n;
  218. {
  219.     register int thiscmd, c;
  220.     register BUFFER *bp;
  221.     char *bufn;
  222.  
  223.     if (curbp->b_bufp == NULL) {
  224.         TTbeep();
  225.         mlforce("[No other buffers.]");
  226.         return(FALSE);
  227.     }
  228.  
  229.     if (f == FALSE) {
  230.         hist_show();
  231.         thiscmd = lastcmd;
  232.         c = kbd_seq();
  233.         mlerase();
  234.         if (c == thiscmd) {
  235.             c = 1;
  236.         } else if (isdigit(c)) {
  237.             c = c - '0';
  238.         } else {
  239.             tungetc(c);
  240.             return FALSE;
  241.         }
  242.     } else {
  243.         c = n;
  244.     }
  245.         
  246.     bufn = hist_lookup(c);
  247.     if (bufn == NULL) {
  248.         TTbeep();
  249.         mlforce("[No such buffer.]");
  250.         return FALSE;
  251.     }
  252.     /* first assume its a buffer name, then a file name */
  253.     if ((bp=bfind(bufn, NO_CREAT, 0)) == NULL)
  254.         return getfile(bufn,TRUE);
  255.     else {
  256.         return swbuffer(bp);
  257.     }
  258. }
  259.  
  260. /* switch back to the most recent buffer */
  261. /* ARGSUSED */
  262. int
  263. altbuff(f,n)
  264. int f,n;
  265. {
  266.     return histbuff(TRUE,1);
  267. }
  268.  
  269. /*
  270.  * Attach a buffer to a window. The
  271.  * values of dot and mark come from the buffer
  272.  * if the use count is 0. Otherwise, they come
  273.  * from some other window.
  274.  */
  275. /* ARGSUSED */
  276. int
  277. usebuffer(f, n)
  278. int f,n;
  279. {
  280.     register BUFFER *bp;
  281.     register int    s;
  282.     char        bufn[NBUFN];
  283.  
  284.     bufn[0] = 0;
  285.     if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE)
  286.         return s;
  287.     if ((bp=bfind(bufn, OK_CREAT, 0)) == NULL)
  288.         return FALSE;
  289.     return swbuffer(bp);
  290. }
  291.  
  292. /* ARGSUSED */
  293. int
  294. nextbuffer(f, n)    /* switch to the next buffer in the buffer list */
  295. int f, n;    /* default flag, numeric argument */
  296. {
  297.     register BUFFER *bp;    /* eligible buffer to switch to*/
  298.     register BUFFER *stopatbp;    /* eligible buffer to switch to*/
  299.         
  300.     stopatbp = NULL;
  301.     while (stopatbp != bheadp) {
  302.         /* get the last buffer in the list */
  303.         bp = bheadp;
  304.         while(bp->b_bufp != stopatbp)
  305.             bp = bp->b_bufp;
  306.         /* if that one's invisible, back up and try again */
  307.         if (bp->b_flag & BFINVS)
  308.             stopatbp = bp;
  309.         else
  310.             return swbuffer(bp);
  311.     }
  312.     /* we're back to the top -- they were all invisible */
  313.     return swbuffer(stopatbp);
  314.         
  315. }
  316.  
  317. /* bring nbp to the top of the list, where curbp _always_ lives */
  318. void
  319. make_current(nbp)
  320. BUFFER *nbp;
  321. {
  322.     register BUFFER *bp;
  323.         
  324.     if (nbp == bheadp) {    /* already at the head */
  325.         curbp = bheadp;
  326.         curtabval = tabstop_val(curbp);
  327.         curswval = shiftwid_val(curbp);
  328.         return;
  329.     }
  330.             
  331.     /* remove nbp from the list */
  332.     bp = bheadp; while(bp->b_bufp != nbp)
  333.         bp = bp->b_bufp;
  334.     bp->b_bufp = nbp->b_bufp;
  335.         
  336.     /* put it at the head */
  337.     nbp->b_bufp = bheadp;
  338.         
  339.     bheadp = nbp;
  340.     curbp = nbp;
  341.  
  342.     curtabval = tabstop_val(curbp);
  343.     curswval = shiftwid_val(curbp);
  344. }
  345.  
  346.  
  347. int
  348. swbuffer(bp)    /* make buffer BP current */
  349. register BUFFER *bp;
  350. {
  351.  
  352.     if (!bp) {
  353.         mlforce("BUG:  swbuffer passed null bp");
  354.         return FALSE;
  355.     }
  356.  
  357.     if (curbp == bp)  /* no switching to be done */
  358.         return TRUE;
  359.  
  360.     if (curbp) {
  361.         /* if we'll have to take over this window, and it's the last */
  362.         if (bp->b_nwnd == 0 && --curbp->b_nwnd == 0) {
  363.             undispbuff(curbp,curwp);
  364.         }
  365.     }
  366.     make_current(bp);    /* sets curbp */
  367.  
  368.     /* get it already on the screen if possible */
  369.     if (bp->b_nwnd > 0)  { /* then it's on the screen somewhere */
  370.         register WINDOW *wp;
  371.         wp = wheadp;
  372.         while (wp->w_bufp != bp && wp->w_wndp != NULL)
  373.             wp = wp->w_wndp;
  374.         if (!wp)
  375.             mlforce("BUG: swbuffer: wp still NULL");
  376.         curwp = wp;
  377.         upmode();
  378.         return TRUE;
  379.     }
  380.         
  381.     /* oh well, suck it into this window */
  382.     curwp->w_bufp  = bp;
  383.     curwp->w_flag |= WFMODE|WFHARD; /* Quite nasty.     */
  384.     if (bp->b_nwnd++ == 0) {        /* First use.        */
  385.         curwp->w_traits = bp->b_wtraits;
  386.     }
  387.     if (bp->b_active != TRUE) {        /* buffer not active yet*/
  388.         /* read it in and activate it */
  389.         (void)readin(bp->b_fname, TRUE, bp, TRUE);
  390.         curwp->w_dot.l = lforw(bp->b_line.l);
  391.         curwp->w_dot.o = 0;
  392.         bp->b_active = TRUE;
  393.     }
  394. #if    NeWS
  395.     newsreportmodes() ;
  396. #endif
  397.     return TRUE;
  398. }
  399.  
  400.  
  401. void
  402. undispbuff(bp,wp)
  403. register BUFFER *bp;
  404. register WINDOW *wp;
  405. {
  406.     /* get rid of it completely if it's a scratch buffer,
  407.         or it's empty and unmodified */
  408.     if ( (bp->b_flag & BFSCRTCH) || 
  409.         ( !(bp->b_flag & BFCHG) && is_empty_buf(bp)) ) {
  410.         (void)zotbuf(bp);
  411.     } else {  /* otherwise just adjust it off the screen */
  412.         bp->b_wtraits  = wp->w_traits;
  413.     }
  414. }
  415.  
  416. /* return the correct tabstop setting for this buffer */
  417. int
  418. tabstop_val(bp)
  419. register BUFFER *bp;
  420. {
  421.     if (is_local_b_val(bp,MDCMOD))
  422.         return b_val(bp,
  423.             b_val(bp, MDCMOD) ? VAL_C_TAB : VAL_TAB);
  424.     else
  425.         return b_val(bp,
  426.             (b_val(bp, MDCMOD) && has_C_suffix(bp))
  427.                      ? VAL_C_TAB : VAL_TAB);
  428. }
  429.  
  430. /* return the correct shiftwidth setting for this buffer */
  431. int
  432. shiftwid_val(bp)
  433. register BUFFER *bp;
  434. {
  435.     if (is_local_b_val(bp,MDCMOD))
  436.         return b_val(bp,
  437.             b_val(bp, MDCMOD) ? VAL_C_SWIDTH : VAL_SWIDTH);
  438.     else
  439.         return b_val(bp,
  440.             (b_val(bp, MDCMOD) && has_C_suffix(bp))
  441.                      ? VAL_C_SWIDTH : VAL_SWIDTH);
  442. }
  443.  
  444. int
  445. has_C_suffix(bp)
  446. register BUFFER *bp;
  447. {
  448.     int s;
  449.     ignorecase = FALSE;
  450.     s =  regexec(b_val_rexp(bp,VAL_CSUFFIXES)->reg,
  451.             bp->b_fname, NULL, 0, -1);
  452.     return s;
  453. }
  454.  
  455. /*
  456.  * Dispose of a buffer, by name.
  457.  * Ask for the name. Look it up (don't get too
  458.  * upset if it isn't there at all!). Get quite upset
  459.  * if the buffer is being displayed. Clear the buffer (ask
  460.  * if the buffer has been changed). Then free the header
  461.  * line and the buffer header.
  462.  */
  463. /* ARGSUSED */
  464. int
  465. killbuffer(f, n)
  466. int f,n;
  467. {
  468.     register BUFFER *bp;
  469.     register int    s;
  470.     char bufn[NBUFN];
  471.     register BUFFER *bp1;
  472.  
  473.     bufn[0] = 0;
  474.     if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE)
  475.         return(s);
  476.     if ((bp=bfind(bufn, NO_CREAT, 0)) == NULL) { /* Easy if unknown.     */
  477.         mlforce("[No such buffer]");
  478.         return FALSE;
  479.     }
  480. #ifdef BEFORE /* now allow killing the specials, like "tags" */
  481.     if(bp->b_flag & BFINVS)     /* Deal with special buffers    */
  482.             return (TRUE);        /* by doing nothing.    */
  483. #endif
  484.     if (curbp == bp) {
  485.         if (histbuff(TRUE,1) != TRUE) {
  486.             mlforce("[Can't kill that buffer]");
  487.             return FALSE;
  488.         }
  489.     }
  490.     if (bp->b_nwnd > 0)  { /* then it's on the screen somewhere */
  491.         register WINDOW *wp;
  492.         for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  493.             if (wp->w_bufp == bp) {
  494.                 delwp(wp);
  495.             }
  496.         }
  497.         for (bp1 = bheadp; bp1; bp1 = bp1->b_bufp) {
  498.             if (bp1 == bp)
  499.                 break;
  500.         }
  501.         if (bp1 == NULL)  /* delwp must have zotted us */
  502.             return TRUE;
  503.     }
  504.     s = zotbuf(bp);
  505.     if (s == TRUE)
  506.         mlwrite("Buffer %s gone", bufn);
  507.     return s;
  508. }
  509.  
  510. int
  511. zotbuf(bp)    /* kill the buffer pointed to by bp */
  512. register BUFFER *bp;
  513. {
  514.     register BUFFER *bp1;
  515.     register BUFFER *bp2;
  516.     register int    s;
  517.     register int    didswitch = FALSE;
  518.  
  519. #define no_del 
  520. #ifdef no_del
  521.     if (bp->b_nwnd != 0) {            /* Error if on screen.    */
  522.         mlforce("[Buffer is being displayed]");
  523.         return (FALSE);
  524.     }
  525. #else
  526.     if (curbp == bp) {
  527.         didswitch = TRUE;
  528.         if (histbuff(TRUE,1) != TRUE) {
  529.             mlforce("[Can't kill that buffer]");
  530.             return FALSE;
  531.         }
  532.     }
  533.     if (bp->b_nwnd > 0)  { /* then it's on the screen somewhere */
  534.         register WINDOW *wp;
  535.         for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  536.             if (wp->w_bufp == bp) {
  537.                 delwp(wp);
  538.             }
  539.         }
  540.         for (bp1 = bheadp; bp1; bp1 = bp1->b_bufp) {
  541.             if (bp1 == bp)
  542.                 break;
  543.         }
  544.         if (bp1 == NULL)  /* delwp must have zotted us */
  545.             return TRUE;
  546.     }
  547.  
  548.         
  549. #endif
  550.     /* Blow text away.    */
  551.     if ((s=bclear(bp)) != TRUE) {
  552.         /* the user must have answered no */
  553.         if (didswitch)
  554.             swbuffer(bp);
  555.         return (s);
  556.     }
  557.             
  558.     lfree(bp->b_line.l,bp);     /* Release header line. */
  559.     bp1 = NULL;                /* Find the header.    */
  560.     bp2 = bheadp;
  561.     while (bp2 != bp) {
  562.         bp1 = bp2;
  563.         bp2 = bp2->b_bufp;
  564.     }
  565.     bp2 = bp2->b_bufp;            /* Next one in chain.    */
  566.     if (bp1 == NULL)            /* Unlink it.        */
  567.         bheadp = bp2;
  568.     else
  569.         bp1->b_bufp = bp2;
  570.     free((char *) bp);            /* Release buffer block */
  571.     return (TRUE);
  572. }
  573.  
  574. /* ARGSUSED */
  575. int
  576. namebuffer(f,n)     /*    Rename the current buffer    */
  577. int f, n;        /* default Flag & Numeric arg */
  578. {
  579.     register BUFFER *bp;    /* pointer to scan through all buffers */
  580.     static char bufn[NBUFN];    /* buffer to hold buffer name */
  581.     char *prompt = "New name for buffer: ";
  582.  
  583.     /* prompt for and get the new buffer name */
  584. ask:    if (mlreply(prompt, bufn, NBUFN) != TRUE)
  585.         return(FALSE);
  586.  
  587.     /* and check for duplicates */
  588.     bp = bheadp;
  589.     while (bp != NULL) {
  590.         if (bp != curbp) {
  591.             /* if the names the same */
  592.             if (strcmp(bufn, bp->b_bname) == 0) {
  593.                 prompt = "That name's been used.  New name: ";
  594.                 goto ask;  /* try again */
  595.             }
  596.         }
  597.         bp = bp->b_bufp;    /* onward */
  598.     }
  599.  
  600.     strcpy(curbp->b_bname, bufn);    /* copy buffer name to structure */
  601.     curwp->w_flag |= WFMODE;    /* make mode line replot */
  602.     mlerase();
  603.     return(TRUE);
  604. }
  605.  
  606. /* create or find a window, and stick this buffer in it.  when 
  607.     done, we own the window and the buffer, but they are _not_
  608.     necessarily curwp and curbp */
  609. int
  610. popupbuff(bp)
  611. BUFFER *bp;
  612. {
  613.     register WINDOW *wp;
  614.  
  615.     if (!curbp) {
  616.         curbp = bp;  /* possibly at startup time */
  617.         curwp->w_bufp = curbp;
  618.         ++curbp->b_nwnd;
  619.     } else if (bp->b_nwnd == 0) {           /* Not on screen yet.   */
  620.         if ((wp = wpopup()) == NULL)
  621.             return FALSE;
  622.         if (--wp->w_bufp->b_nwnd == 0)
  623.             undispbuff(wp->w_bufp,wp);
  624.         wp->w_bufp  = bp;
  625.         ++bp->b_nwnd;
  626.     }
  627.     wp = wheadp;
  628.     while (wp != NULL) {
  629.         if (wp->w_bufp == bp) {
  630.             wp->w_line.l = lforw(bp->b_line.l);
  631.             wp->w_dot.l  = lforw(bp->b_line.l);
  632.             wp->w_dot.o  = 0;
  633. #ifdef WINMARK
  634.             wp->w_mark = nullmark;
  635. #endif
  636.             wp->w_lastdot = nullmark;
  637.             wp->w_values = global_w_values;
  638.             wp->w_flag |= WFMODE|WFHARD;
  639.                     
  640.         }
  641.         wp = wp->w_wndp;
  642.     }
  643.     swbuffer(bp);
  644.     return TRUE;
  645. }
  646.  
  647. /*
  648.     List all of the active buffers.  First update the special
  649.     buffer that holds the list.  Next make sure at least 1
  650.     window is displaying the buffer list, splitting the screen
  651.     if this is what it takes.  Lastly, repaint all of the
  652.     windows that are displaying the list.
  653.     A numeric argument forces it to list invisible buffers as
  654.     well.
  655. */
  656.  
  657. #define BUFFER_LIST_NAME "[Buffer List]"
  658.  
  659. int
  660. togglelistbuffers(f, n)
  661. int f,n;
  662. {
  663.     register WINDOW *wp;
  664.     register BUFFER *bp;
  665.     int s;
  666.  
  667.     /* if it doesn't exist, create it */
  668.     if ((bp = bfind(BUFFER_LIST_NAME, NO_CREAT, BFSCRTCH)) == NULL)
  669.         return listbuffers(f,n);
  670.  
  671.     /* if it does exist, delete the window, which in turn 
  672.         will kill the BFSCRTCH buffer */
  673.     wp = wheadp;
  674.     s = TRUE;
  675.     while (wp != NULL && s) {
  676.         if (wp->w_bufp == bp) {
  677.             s = delwp(wp);
  678.             break;
  679.         }
  680.         wp = wp->w_wndp;
  681.     }
  682.     return s;
  683. }
  684.  
  685. /* ARGSUSED */
  686. int
  687. listbuffers(f, n)
  688. int f,n;
  689. {
  690.     return liststuff(BUFFER_LIST_NAME, makebufflist, f, NULL);
  691. }
  692.  
  693. /*
  694.  * This routine rebuilds the
  695.  * text in the buffer
  696.  * that holds the buffer list. It is called
  697.  * by the list buffers command. Return TRUE
  698.  * if everything works. Return FALSE if there
  699.  * is an error (if there is no memory). Iflag
  700.  * indicates whether to list hidden buffers.
  701.  */
  702. /* ARGSUSED */
  703. void
  704. makebufflist(iflag,dummy)
  705. int iflag;    /* list hidden buffer flag */
  706. char *dummy;
  707. {
  708.     register BUFFER *bp;
  709.     int nbuf = 1;    /* no. of buffers */
  710.     long nbytes;        /* # of bytes in current buffer */
  711.     int footnote = FALSE;
  712.  
  713.     bprintf("     %7s %*s %s\n", "Size",NBUFN,"Buffer name","Contents");
  714.     bprintf("     %7p %*p %30p\n", '-',NBUFN,'-','-');
  715.             
  716.     bp = bheadp;                /* For all buffers    */
  717.  
  718.     /* output the list of buffers */
  719.     while (bp != NULL) {
  720.         /* skip invisible buffers and ourself if iflag is false */
  721.         if (((bp->b_flag&(BFINVS|BFSCRTCH)) != 0) && (iflag != TRUE)) {
  722.             bp = bp->b_bufp;
  723.             continue;
  724.         }
  725.         /* output status of ACTIVE flag (has the file been read in? */
  726.         if (bp->b_active == TRUE) {   /* if activated        */
  727.             if ((bp->b_flag&BFCHG) != 0) {      /* if changed     */
  728.                 bputc('m');
  729.                 footnote = TRUE;
  730.             } else {
  731.                 bputc(' ');
  732.             }
  733.         } else {
  734.             bputc('u');
  735.             footnote = TRUE;
  736.         }
  737.  
  738.         bprintf(" %2d ",nbuf++);
  739.  
  740.         {    /* Count bytes in buf.    */
  741.             register LINE    *lp;
  742.             nbytes = 0L;
  743.             lp = lforw(bp->b_line.l);
  744.             while (lp != bp->b_line.l) {
  745.                 nbytes += (long)llength(lp)+1L;
  746.                 lp = lforw(lp);
  747.             }
  748.         }
  749.         bprintf("%7ld %*s ",nbytes, NBUFN, bp->b_bname );
  750.         {
  751.             char *p;
  752.             p = shorten_path(bp->b_fname);
  753.             if (p) {
  754. #if MSDOS
  755.                 if (isupper(p[0]) && p[1] == ':') {
  756.                     bprintf("%c:",p[0]);
  757.                     p += 2;
  758.                 }
  759. #endif
  760.                 if (p[0] != slash && p[0] != '.' && 
  761.                         p[0] != '!' && !isspace(p[0]))
  762.                     bprintf(".%c",slash);
  763.                 bprintf("%s",p);
  764.             }
  765.         }
  766.         bprintf("\n");
  767.         bp = bp->b_bufp;
  768.     }
  769.  
  770.     if (footnote == TRUE)
  771.         bprintf("('m' means modified, 'u' means unread)\n");
  772.  
  773.     bprintf("             %*s %s\n", NBUFN, "Current dir:",
  774.         current_directory(FALSE));
  775. }
  776.  
  777. #ifdef NEEDED
  778. ltoa(buf, width, num)
  779. char   buf[];
  780. int    width;
  781. long   num;
  782. {
  783.     buf[width] = 0;             /* End of string.    */
  784.     while (num >= 10) {            /* Conditional digits.    */
  785.         buf[--width] = (int)(num%10L) + '0';
  786.         num /= 10L;
  787.     }
  788.     buf[--width] = (int)num + '0';        /* Always 1 digit.    */
  789.     while (width != 0)            /* Pad with blanks.    */
  790.         buf[--width] = ' ';
  791. }
  792. #endif
  793.  
  794. /*
  795.  * The argument "text" points to
  796.  * a string. Append this line to the
  797.  * buffer. Handcraft the EOL
  798.  * on the end. Return TRUE if it worked and
  799.  * FALSE if you ran out of room.
  800.  */
  801. int
  802. addline(bp,text,len)
  803. register BUFFER *bp;
  804. char    *text;
  805. int len;
  806. {
  807.     register LINE    *lp;
  808.     register int    i;
  809.     register int    ntext;
  810.  
  811.     ntext = (len < 0) ? strlen(text) : len;
  812.     if ((lp=lalloc(ntext,bp)) == NULL)
  813.         return (FALSE);
  814.     for (i=0; i<ntext; ++i)
  815.         lputc(lp, i, text[i]);
  816.     bp->b_line.l->l_bp->l_fp = lp;         /* Hook onto the end    */
  817.     lp->l_bp = bp->b_line.l->l_bp;
  818.     bp->b_line.l->l_bp = lp;
  819.     lp->l_fp = bp->b_line.l;
  820.     if (sameline(bp->b_dot, bp->b_line))  /* If "." is at the end */
  821.         bp->b_dot.l = lp;         /* move it to new line  */
  822.     return (TRUE);
  823. }
  824.  
  825. /*
  826.  * Look through the list of
  827.  * buffers. Return TRUE if there
  828.  * are any changed buffers. Buffers
  829.  * that hold magic internal stuff are
  830.  * not considered; who cares if the
  831.  * list of buffer names is hacked.
  832.  * Return FALSE if no buffers
  833.  * have been changed.
  834.  */
  835. int
  836. anycb()
  837. {
  838.     register BUFFER *bp;
  839.     register int cnt = 0;
  840.  
  841.     bp = bheadp;
  842.     while (bp != NULL) {
  843.         if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
  844.             cnt++;
  845.         bp = bp->b_bufp;
  846.     }
  847.     return (cnt);
  848. }
  849.  
  850. /*
  851.  * Find a buffer, by name. Return a pointer
  852.  * to the BUFFER structure associated with it.
  853.  * If the buffer is not found
  854.  * and the "cflag" is OK_CREAT, create it. The "bflag" is
  855.  * the settings for the flags in in buffer.
  856.  */
  857. BUFFER    *
  858. bfind(bname, cflag, bflag)
  859. int cflag, bflag;
  860. char   *bname;
  861. {
  862.     register BUFFER *bp;
  863.     register LINE    *lp;
  864.     register BUFFER *lastb = NULL;    /* buffer to insert after */
  865.  
  866.     bp = bheadp;
  867.     while (bp != NULL) {
  868.         if (strncmp(bname, bp->b_bname, NBUFN) == 0)
  869.             return (bp);
  870.         lastb = bp;
  871.         bp = bp->b_bufp;
  872.     }
  873.     if (cflag == NO_CREAT)    /* don't create it */
  874.         return NULL;
  875.         
  876.     if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
  877.         return (NULL);
  878.  
  879.     /* these affect lalloc(), below */
  880.     bp->b_LINEs = NULL;
  881.     bp->b_LINEs_end = NULL;
  882.     bp->b_freeLINEs = NULL;
  883.     bp->b_ltext = NULL;
  884.     bp->b_ltext_end = NULL;
  885.  
  886.     if ((lp=lalloc(0,bp)) == NULL) {
  887.         free((char *) bp);
  888.         return (NULL);
  889.     }
  890.  
  891.     /* and set up the other buffer fields */
  892.     bp->b_active = FALSE;
  893.     bp->b_dot.l  = lp;
  894.     bp->b_dot.o  = 0;
  895. #if WINMARK
  896.     bp->b_mark = nullmark;
  897. #endif
  898.     bp->b_lastdot = nullmark;
  899.     bp->b_nmmarks = NULL;
  900.     bp->b_flag  = bflag;
  901.     bp->b_values = global_b_values;
  902.     bp->b_wtraits.w_vals = global_w_values;
  903.     bp->b_nwnd  = 0;
  904.     bp->b_wline.l = lp;
  905.     bp->b_wline.o = 0;  /* unused */
  906.     bp->b_line.l = lp;
  907.     bp->b_line.o = 0;
  908.     bp->b_acount = b_val(bp, VAL_ASAVECNT);
  909.     bp->b_fname = NULL;
  910.     ch_fname(bp, "");
  911.     strcpy(bp->b_bname, bname);
  912. #if    CRYPT
  913.     bp->b_key[0] = 0;
  914. #endif
  915.     bp->b_udstks[0] = bp->b_udstks[1] = NULL;
  916.     bp->b_udstkindx = 0;
  917.     bp->b_ulinep = NULL;
  918.     lp->l_fp = lp;
  919.     lp->l_bp = lp;
  920.         
  921.     /* append at the end */
  922.     if (lastb)
  923.         lastb->b_bufp = bp;
  924.     else
  925.         bheadp = bp;
  926.     bp->b_bufp = NULL;
  927.  
  928.     return (bp);
  929. }
  930.  
  931. /*
  932.  * This routine blows away all of the text
  933.  * in a buffer. If the buffer is marked as changed
  934.  * then we ask if it is ok to blow it away; this is
  935.  * to save the user the grief of losing text. The
  936.  * window chain is nearly always wrong if this gets
  937.  * called; the caller must arrange for the updates
  938.  * that are required. Return TRUE if everything
  939.  * looks good.
  940.  */
  941. int
  942. bclear(bp)
  943. register BUFFER *bp;
  944. {
  945.     register LINE    *lp;
  946.  
  947.     if ((bp->b_flag&(BFINVS|BFSCRTCH)) == 0 /* Not invisible or scratch */
  948.             && (bp->b_flag&BFCHG) != 0 ) {        /* Something changed    */
  949.         char ques[50];
  950.         strcpy(ques,"Discard changes to ");
  951.         strcat(ques,bp->b_bname);
  952.         if (mlyesno(ques) != TRUE)
  953.             return FALSE;
  954.     }
  955.     bp->b_flag  &= ~BFCHG;            /* Not changed        */
  956.     freeundostacks(bp);    /* do this before removing lines */
  957.     while ((lp=lforw(bp->b_line.l)) != bp->b_line.l) {
  958.         lremove(bp,lp);
  959.         lfree(lp,bp);
  960.     }
  961.     if (bp->b_ltext) {
  962.         free((char *)(bp->b_ltext));
  963.         bp->b_ltext = NULL;
  964.         bp->b_ltext_end = NULL;
  965.     }
  966.     if (bp->b_LINEs) {
  967.         free((char *)(bp->b_LINEs));
  968.         bp->b_LINEs = NULL;
  969.         bp->b_LINEs_end = NULL;
  970.     }
  971.     bp->b_freeLINEs = NULL;
  972.     bp->b_dot  = bp->b_line;        /* Fix "."        */
  973. #if WINMARK
  974.     bp->b_mark = nullmark;            /* Invalidate "mark"    */
  975. #endif
  976.     bp->b_lastdot = nullmark;        /* Invalidate "mark"    */
  977.     if (bp->b_nmmarks != NULL) { /* free the named marks */
  978.         free((char *)(bp->b_nmmarks));
  979.         bp->b_nmmarks = NULL;
  980.     }
  981.     return (TRUE);
  982. }
  983.  
  984. /* ARGSUSED */
  985. int
  986. unmark(f, n)    /* unmark the current buffers change flag */
  987. int f, n;    /* unused command arguments */
  988. {
  989.     curbp->b_flag &= ~BFCHG;
  990.     curwp->w_flag |= WFMODE;
  991.     return(TRUE);
  992. }
  993.