]> pd.if.org Git - pd_readline/blob - mg/buffer.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / buffer.c
1 /*      $OpenBSD: buffer.c,v 1.78 2012/03/14 13:56:35 lum Exp $ */
2
3 /* This file is in the public domain. */
4
5 /*
6  *              Buffer handling.
7  */
8
9 #include "def.h"
10 #include "kbd.h"                /* needed for modes */
11
12 #include <libgen.h>
13 #include <stdarg.h>
14
15 static struct buffer  *makelist(void);
16 static struct buffer *bnew(const char *);
17
18 static int usebufname(const char *);
19
20 /* Flag for global working dir */
21 extern int globalwd;
22
23 /* ARGSUSED */
24 int
25 togglereadonly(int f, int n)
26 {
27         int s;
28
29         if ((s = checkdirty(curbp)) != TRUE)
30                 return (s);
31         if (!(curbp->b_flag & BFREADONLY))
32                 curbp->b_flag |= BFREADONLY;
33         else {
34                 curbp->b_flag &= ~BFREADONLY;
35                 if (curbp->b_flag & BFCHG)
36                         ewprintf("Warning: Buffer was modified");
37         }
38         curwp->w_rflag |= WFMODE;
39
40         return (TRUE);
41 }
42
43 /* Switch to the named buffer.
44  * If no name supplied, switch to the default (alternate) buffer.
45  */
46 int
47 usebufname(const char *bufp)
48 {
49         struct buffer *bp;
50
51         if (bufp == NULL)
52                 return (ABORT);
53         if (bufp[0] == '\0' && curbp->b_altb != NULL)
54                 bp = curbp->b_altb;
55         else if ((bp = bfind(bufp, TRUE)) == NULL)
56                 return (FALSE);
57
58         /* and put it in current window */
59         curbp = bp;
60         return (showbuffer(bp, curwp, WFFRAME | WFFULL));
61 }
62
63 /*
64  * Attach a buffer to a window. The values of dot and mark come
65  * from the buffer if the use count is 0. Otherwise, they come
66  * from some other window.  *scratch* is the default alternate
67  * buffer.
68  */
69 /* ARGSUSED */
70 int
71 usebuffer(int f, int n)
72 {
73         char    bufn[NBUFN], *bufp;
74
75         /* Get buffer to use from user */
76         if ((curbp->b_altb == NULL) &&
77             ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
78                 bufp = eread("Switch to buffer: ", bufn, NBUFN, EFNEW | EFBUF);
79         else
80                 bufp = eread("Switch to buffer: (default %s) ", bufn, NBUFN,
81                     EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname);
82
83         return (usebufname(bufp));
84 }
85
86 /*
87  * pop to buffer asked for by the user.
88  */
89 /* ARGSUSED */
90 int
91 poptobuffer(int f, int n)
92 {
93         struct buffer *bp;
94         struct mgwin  *wp;
95         char    bufn[NBUFN], *bufp;
96
97         /* Get buffer to use from user */
98         if ((curbp->b_altb == NULL) &&
99             ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL))
100                 bufp = eread("Switch to buffer in other window: ", bufn, NBUFN,
101                     EFNEW | EFBUF);
102         else
103                 bufp = eread("Switch to buffer in other window: (default %s) ",
104                     bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname);
105         if (bufp == NULL)
106                 return (ABORT);
107         if (bufp[0] == '\0' && curbp->b_altb != NULL)
108                 bp = curbp->b_altb;
109         else if ((bp = bfind(bufn, TRUE)) == NULL)
110                 return (FALSE);
111         if (bp == curbp)
112                 return (splitwind(f, n));
113         /* and put it in a new, non-ephemeral window */
114         if ((wp = popbuf(bp, WNONE)) == NULL)
115                 return (FALSE);
116         curbp = bp;
117         curwp = wp;
118         return (TRUE);
119 }
120
121 /*
122  * Dispose of a buffer, by name.
123  * Ask for the name. Look it up (don't get too
124  * upset if it isn't there at all!). Clear the buffer (ask
125  * if the buffer has been changed). Then free the header
126  * line and the buffer header. Bound to "C-X k".
127  */
128 /* ARGSUSED */
129 int
130 killbuffer_cmd(int f, int n)
131 {
132         struct buffer *bp;
133         char    bufn[NBUFN], *bufp;
134
135         if ((bufp = eread("Kill buffer: (default %s) ", bufn, NBUFN,
136             EFNUL | EFNEW | EFBUF, curbp->b_bname)) == NULL)
137                 return (ABORT);
138         else if (bufp[0] == '\0')
139                 bp = curbp;
140         else if ((bp = bfind(bufn, FALSE)) == NULL)
141                 return (FALSE);
142         return (killbuffer(bp));
143 }
144
145 int
146 killbuffer(struct buffer *bp)
147 {
148         struct buffer *bp1;
149         struct buffer *bp2;
150         struct mgwin  *wp;
151         int s;
152         struct undo_rec *rec, *next;
153
154         /*
155          * Find some other buffer to display. Try the alternate buffer,
156          * then the first different buffer in the buffer list.  If there's
157          * only one buffer, create buffer *scratch* and make it the alternate
158          * buffer.  Return if *scratch* is only buffer...
159          */
160         if ((bp1 = bp->b_altb) == NULL) {
161                 bp1 = (bp == bheadp) ? bp->b_bufp : bheadp;
162                 if (bp1 == NULL) {
163                         /* only one buffer. see if it's *scratch* */
164                         if (bp == bfind("*scratch*", FALSE))
165                                 return (TRUE);
166                         /* create *scratch* for alternate buffer */
167                         if ((bp1 = bfind("*scratch*", TRUE)) == NULL)
168                                 return (FALSE);
169                 }
170         }
171         if ((s = bclear(bp)) != TRUE)
172                 return (s);
173         for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) {
174                 if (wp->w_bufp == bp) {
175                         bp2 = bp1->b_altb;      /* save alternate buffer */
176                         if (showbuffer(bp1, wp, WFMODE | WFFRAME | WFFULL))
177                                 bp1->b_altb = bp2;
178                         else
179                                 bp1 = bp2;
180                 }
181         }
182         if (bp == curbp)
183                 curbp = bp1;
184         free(bp->b_headp);                      /* Release header line.  */
185         bp2 = NULL;                             /* Find the header.      */
186         bp1 = bheadp;
187         while (bp1 != bp) {
188                 if (bp1->b_altb == bp)
189                         bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
190                 bp2 = bp1;
191                 bp1 = bp1->b_bufp;
192         }
193         bp1 = bp1->b_bufp;                      /* Next one in chain.    */
194         if (bp2 == NULL)                        /* Unlink it.            */
195                 bheadp = bp1;
196         else
197                 bp2->b_bufp = bp1;
198         while (bp1 != NULL) {                   /* Finish with altb's    */
199                 if (bp1->b_altb == bp)
200                         bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb;
201                 bp1 = bp1->b_bufp;
202         }
203         rec = TAILQ_FIRST(&bp->b_undo);
204
205         while (rec != NULL) {
206                 next = TAILQ_NEXT(rec, next);
207                 free_undo_record(rec);
208                 rec = next;
209         }
210
211         free(bp->b_bname);                      /* Release name block    */
212         free(bp);                               /* Release buffer block */
213         return (TRUE);
214 }
215
216 /*
217  * Save some buffers - just call anycb with the arg flag.
218  */
219 /* ARGSUSED */
220 int
221 savebuffers(int f, int n)
222 {
223         if (anycb(f) == ABORT)
224                 return (ABORT);
225         return (TRUE);
226 }
227
228 /*
229  * Listing buffers.
230  */
231 static int listbuf_ncol;
232
233 static int      listbuf_goto_buffer(int f, int n);
234 static int      listbuf_goto_buffer_one(int f, int n);
235 static int      listbuf_goto_buffer_helper(int f, int n, int only);
236
237 static PF listbuf_pf[] = {
238         listbuf_goto_buffer
239 };
240 static PF listbuf_one[] = {
241         listbuf_goto_buffer_one
242 };
243
244
245 static struct KEYMAPE (2 + IMAPEXT) listbufmap = {
246         2,
247         2 + IMAPEXT,
248         rescan,
249         {
250                 {
251                         CCHR('M'), CCHR('M'), listbuf_pf, NULL
252                 },
253                 {
254                         '1', '1', listbuf_one, NULL
255                 }
256         }
257 };
258
259 /*
260  * Display the buffer list. This is done
261  * in two parts. The "makelist" routine figures out
262  * the text, and puts it in a buffer. "popbuf"
263  * then pops the data onto the screen. Bound to
264  * "C-X C-B".
265  */
266 /* ARGSUSED */
267 int
268 listbuffers(int f, int n)
269 {
270         static int               initialized = 0;
271         struct buffer           *bp;
272         struct mgwin            *wp;
273
274         if (!initialized) {
275                 maps_add((KEYMAP *)&listbufmap, "listbufmap");
276                 initialized = 1;
277         }
278
279         if ((bp = makelist()) == NULL || (wp = popbuf(bp, WNONE)) == NULL)
280                 return (FALSE);
281         wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */
282         wp->w_doto = bp->b_doto;
283         bp->b_modes[0] = name_mode("fundamental");
284         bp->b_modes[1] = name_mode("listbufmap");
285         bp->b_nmodes = 1;
286
287         return (TRUE);
288 }
289
290 /*
291  * This routine rebuilds the text for the
292  * list buffers command. Return pointer
293  * to new list if everything works.
294  * Return NULL if there is an error (if
295  * there is no memory).
296  */
297 static struct buffer *
298 makelist(void)
299 {
300         int             w = ncol / 2;
301         struct buffer   *bp, *blp;
302         struct line     *lp;
303
304         if ((blp = bfind("*Buffer List*", TRUE)) == NULL)
305                 return (NULL);
306         if (bclear(blp) != TRUE)
307                 return (NULL);
308         blp->b_flag &= ~BFCHG;          /* Blow away old.        */
309         blp->b_flag |= BFREADONLY;
310
311         listbuf_ncol = ncol;            /* cache ncol for listbuf_goto_buffer */
312
313         if (addlinef(blp, "%-*s%s", w, " MR Buffer", "Size   File") == FALSE ||
314             addlinef(blp, "%-*s%s", w, " -- ------", "----   ----") == FALSE)
315                 return (NULL);
316
317         for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
318                 RSIZE nbytes;
319
320                 nbytes = 0;                     /* Count bytes in buf.   */
321                 if (bp != blp) {
322                         lp = bfirstlp(bp);
323                         while (lp != bp->b_headp) {
324                                 nbytes += llength(lp) + 1;
325                                 lp = lforw(lp);
326                         }
327                         if (nbytes)
328                                 nbytes--;       /* no bonus newline      */
329                 }
330
331                 if (addlinef(blp, "%c%c%c %-*.*s%c%-6d %-*s",
332                     (bp == curbp) ? '.' : ' ',  /* current buffer ? */
333                     ((bp->b_flag & BFCHG) != 0) ? '*' : ' ',    /* changed ? */
334                     ((bp->b_flag & BFREADONLY) != 0) ? ' ' : '*',
335                     w - 5,              /* four chars already written */
336                     w - 5,              /* four chars already written */
337                     bp->b_bname,        /* buffer name */
338                     strlen(bp->b_bname) < w - 5 ? ' ' : '$', /* truncated? */
339                     nbytes,             /* buffer size */
340                     w - 7,              /* seven chars already written */
341                     bp->b_fname) == FALSE)
342                         return (NULL);
343         }
344         blp->b_dotp = bfirstlp(blp);            /* put dot at beginning of
345                                                  * buffer */
346         blp->b_doto = 0;
347         return (blp);                           /* All done              */
348 }
349
350 static int
351 listbuf_goto_buffer(int f, int n)
352 {
353         return (listbuf_goto_buffer_helper(f, n, 0));
354 }
355
356 static int
357 listbuf_goto_buffer_one(int f, int n)
358 {
359         return (listbuf_goto_buffer_helper(f, n, 1));
360 }
361
362 static int
363 listbuf_goto_buffer_helper(int f, int n, int only)
364 {
365         struct buffer   *bp;
366         struct mgwin    *wp;
367         char            *line = NULL;
368         int              i, ret = FALSE;
369
370         if (curwp->w_dotp->l_text[listbuf_ncol/2 - 1] == '$') {
371                 ewprintf("buffer name truncated");
372                 return (FALSE);
373         }
374
375         if ((line = malloc(listbuf_ncol/2)) == NULL)
376                 return (FALSE);
377
378         memcpy(line, curwp->w_dotp->l_text + 4, listbuf_ncol/2 - 5);
379         for (i = listbuf_ncol/2 - 6; i > 0; i--) {
380                 if (line[i] != ' ') {
381                         line[i + 1] = '\0';
382                         break;
383                 }
384         }
385         if (i == 0)
386                 goto cleanup;
387
388         for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
389                 if (strcmp(bp->b_bname, line) == 0)
390                         break;
391         }
392         if (bp == NULL)
393                 goto cleanup;
394
395         if ((wp = popbuf(bp, WNONE)) == NULL)
396                 goto cleanup;
397         curbp = bp;
398         curwp = wp;
399
400         if (only)
401                 ret = (onlywind(f, n));
402         else
403                 ret = TRUE;
404
405 cleanup:
406         free(line);
407
408         return (ret);
409 }
410
411 /*
412  * The argument "fmt" points to a format string.  Append this line to the
413  * buffer. Handcraft the EOL on the end.  Return TRUE if it worked and
414  * FALSE if you ran out of room.
415  */
416 int
417 addlinef(struct buffer *bp, char *fmt, ...)
418 {
419         va_list          ap;
420         struct line     *lp;
421
422         if ((lp = lalloc(0)) == NULL)
423                 return (FALSE);
424         va_start(ap, fmt);
425         if (vasprintf(&lp->l_text, fmt, ap) == -1) {
426                 lfree(lp);
427                 va_end(ap);
428                 return (FALSE);
429         }
430         lp->l_used = strlen(lp->l_text);
431         va_end(ap);
432
433         bp->b_headp->l_bp->l_fp = lp;           /* Hook onto the end     */
434         lp->l_bp = bp->b_headp->l_bp;
435         bp->b_headp->l_bp = lp;
436         lp->l_fp = bp->b_headp;
437         bp->b_lines++;
438
439         return (TRUE);
440 }
441
442 /*
443  * Look through the list of buffers, giving the user a chance to save them.
444  * Return TRUE if there are any changed buffers afterwards.  Buffers that don't
445  * have an associated file don't count.  Return FALSE if there are no changed
446  * buffers.  Return ABORT if an error occurs or if the user presses c-g.
447  */
448 int
449 anycb(int f)
450 {
451         struct buffer   *bp;
452         int              s = FALSE, save = FALSE, ret;
453         char             pbuf[NFILEN + 11];
454
455         for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
456                 if (bp->b_fname != NULL && *(bp->b_fname) != '\0' &&
457                     (bp->b_flag & BFCHG) != 0) {
458                         ret = snprintf(pbuf, sizeof(pbuf), "Save file %s",
459                             bp->b_fname);
460                         if (ret < 0 || ret >= sizeof(pbuf)) {
461                                 ewprintf("Error: filename too long!");
462                                 return (ABORT);
463                         }
464                         if ((f == TRUE || (save = eyorn(pbuf)) == TRUE) &&
465                             buffsave(bp) == TRUE) {
466                                 bp->b_flag &= ~BFCHG;
467                                 upmodes(bp);
468                         } else
469                                 s = TRUE;
470                         if (save == ABORT)
471                                 return (save);
472                         save = TRUE;
473                 }
474         }
475         if (save == FALSE /* && kbdmop == NULL */ )     /* experimental */
476                 ewprintf("(No files need saving)");
477         return (s);
478 }
479
480 /*
481  * Search for a buffer, by name.
482  * If not found, and the "cflag" is TRUE,
483  * create a new buffer. Return pointer to the found
484  * (or new) buffer.
485  */
486 struct buffer *
487 bfind(const char *bname, int cflag)
488 {
489         struct buffer   *bp;
490
491         bp = bheadp;
492         while (bp != NULL) {
493                 if (strcmp(bname, bp->b_bname) == 0)
494                         return (bp);
495                 bp = bp->b_bufp;
496         }
497         if (cflag != TRUE)
498                 return (NULL);
499
500         bp = bnew(bname);
501
502         return (bp);
503 }
504
505 /*
506  * Create a new buffer and put it in the list of
507  * all buffers.
508  */
509 static struct buffer *
510 bnew(const char *bname)
511 {
512         struct buffer   *bp;
513         struct line     *lp;
514         int              i;
515         size_t          len;
516
517         bp = calloc(1, sizeof(struct buffer));
518         if (bp == NULL) {
519                 ewprintf("Can't get %d bytes", sizeof(struct buffer));
520                 return (NULL);
521         }
522         if ((lp = lalloc(0)) == NULL) {
523                 free(bp);
524                 return (NULL);
525         }
526         bp->b_altb = bp->b_bufp = NULL;
527         bp->b_dotp = lp;
528         bp->b_doto = 0;
529         bp->b_markp = NULL;
530         bp->b_marko = 0;
531         bp->b_flag = defb_flag;
532         /* if buffer name starts and ends with '*', we ignore changes */
533         len = strlen(bname);
534         if (len) {
535                 if (bname[0] == '*' && bname[len - 1] == '*')
536                         bp->b_flag |= BFIGNDIRTY;
537         }
538         bp->b_nwnd = 0;
539         bp->b_headp = lp;
540         bp->b_nmodes = defb_nmodes;
541         TAILQ_INIT(&bp->b_undo);
542         bp->b_undoptr = NULL;
543         memset(&bp->b_undopos, 0, sizeof(bp->b_undopos));
544         i = 0;
545         do {
546                 bp->b_modes[i] = defb_modes[i];
547         } while (i++ < defb_nmodes);
548         bp->b_fname[0] = '\0';
549         bp->b_cwd[0] = '\0';
550         bzero(&bp->b_fi, sizeof(bp->b_fi));
551         lp->l_fp = lp;
552         lp->l_bp = lp;
553         bp->b_bufp = bheadp;
554         bheadp = bp;
555         bp->b_dotline = bp->b_markline = 1;
556         bp->b_lines = 1;
557         if ((bp->b_bname = strdup(bname)) == NULL) {
558                 ewprintf("Can't get %d bytes", strlen(bname) + 1);
559                 return (NULL);
560         }
561
562         return (bp);
563 }
564
565 /*
566  * This routine blows away all of the text
567  * in a buffer. If the buffer is marked as changed
568  * then we ask if it is ok to blow it away; this is
569  * to save the user the grief of losing text. The
570  * window chain is nearly always wrong if this gets
571  * called; the caller must arrange for the updates
572  * that are required. Return TRUE if everything
573  * looks good.
574  */
575 int
576 bclear(struct buffer *bp)
577 {
578         struct line     *lp;
579         int              s;
580
581         /* Has buffer changed, and do we care? */
582         if (!(bp->b_flag & BFIGNDIRTY) && (bp->b_flag & BFCHG) != 0 &&
583             (s = eyesno("Buffer modified; kill anyway")) != TRUE)
584                 return (s);
585         bp->b_flag &= ~BFCHG;   /* Not changed           */
586         while ((lp = lforw(bp->b_headp)) != bp->b_headp)
587                 lfree(lp);
588         bp->b_dotp = bp->b_headp;       /* Fix dot */
589         bp->b_doto = 0;
590         bp->b_markp = NULL;     /* Invalidate "mark"     */
591         bp->b_marko = 0;
592         bp->b_dotline = bp->b_markline = 1;
593         bp->b_lines = 1;
594
595         return (TRUE);
596 }
597
598 /*
599  * Display the given buffer in the given window. Flags indicated
600  * action on redisplay. Update modified flag so insert loop can check it.
601  */
602 int
603 showbuffer(struct buffer *bp, struct mgwin *wp, int flags)
604 {
605         struct buffer   *obp;
606         struct mgwin    *owp;
607
608         /* Ensure file has not been modified elsewhere */
609         if (fchecktime(bp) != TRUE)
610                 bp->b_flag |= BFDIRTY;
611
612         if (wp->w_bufp == bp) { /* Easy case! */
613                 wp->w_rflag |= flags;
614                 wp->w_dotp = bp->b_dotp;
615                 wp->w_doto = bp->b_doto;
616                 return (TRUE);
617         }
618         /* First, detach the old buffer from the window */
619         if ((bp->b_altb = obp = wp->w_bufp) != NULL) {
620                 if (--obp->b_nwnd == 0) {
621                         obp->b_dotp = wp->w_dotp;
622                         obp->b_doto = wp->w_doto;
623                         obp->b_markp = wp->w_markp;
624                         obp->b_marko = wp->w_marko;
625                         obp->b_dotline = wp->w_dotline;
626                         obp->b_markline = wp->w_markline;
627                 }
628         }
629         /* Now, attach the new buffer to the window */
630         wp->w_bufp = bp;
631
632         if (bp->b_nwnd++ == 0) {        /* First use.            */
633                 wp->w_dotp = bp->b_dotp;
634                 wp->w_doto = bp->b_doto;
635                 wp->w_markp = bp->b_markp;
636                 wp->w_marko = bp->b_marko;
637                 wp->w_dotline = bp->b_dotline;
638                 wp->w_markline = bp->b_markline;
639         } else
640                 /* already on screen, steal values from other window */
641                 for (owp = wheadp; owp != NULL; owp = wp->w_wndp)
642                         if (wp->w_bufp == bp && owp != wp) {
643                                 wp->w_dotp = owp->w_dotp;
644                                 wp->w_doto = owp->w_doto;
645                                 wp->w_markp = owp->w_markp;
646                                 wp->w_marko = owp->w_marko;
647                                 wp->w_dotline = owp->w_dotline;
648                                 wp->w_markline = owp->w_markline;
649                                 break;
650                         }
651         wp->w_rflag |= WFMODE | flags;
652         return (TRUE);
653 }
654
655 /*
656  * Augment a buffer name with a number, if necessary
657  *
658  * If more than one file of the same basename() is open,
659  * the additional buffers are named "file<2>", "file<3>", and
660  * so forth.  This function adjusts a buffer name to
661  * include the number, if necessary.
662  */
663 int
664 augbname(char *bn, const char *fn, size_t bs)
665 {
666         int      count;
667         size_t   remain, len;
668
669         if ((len = xbasename(bn, fn, bs)) >= bs)
670                 return (FALSE);
671
672         remain = bs - len;
673         for (count = 2; bfind(bn, FALSE) != NULL; count++)
674                 snprintf(bn + len, remain, "<%d>", count);
675
676         return (TRUE);
677 }
678
679 /*
680  * Pop the buffer we got passed onto the screen.
681  * Returns a status.
682  */
683 struct mgwin *
684 popbuf(struct buffer *bp, int flags)
685 {
686         struct mgwin    *wp;
687
688         if (bp->b_nwnd == 0) {  /* Not on screen yet.    */
689                 /* 
690                  * Pick a window for a pop-up.
691                  * If only one window, split the screen.
692                  * Flag the new window as ephemeral
693                  */
694                 if (wheadp->w_wndp == NULL &&
695                     splitwind(FFOTHARG, flags) == FALSE)
696                         return (NULL);
697
698                 /*
699                  * Pick the uppermost window that isn't
700                  * the current window. An LRU algorithm
701                  * might be better. Return a pointer, or NULL on error. 
702                  */
703                 wp = wheadp;
704
705                 while (wp != NULL && wp == curwp)
706                         wp = wp->w_wndp;
707         } else
708                 for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
709                         if (wp->w_bufp == bp) {
710                                 wp->w_rflag |= WFFULL | WFFRAME;
711                                 return (wp);
712                         }
713         if (showbuffer(bp, wp, WFFULL) != TRUE)
714                 return (NULL);
715         return (wp);
716 }
717
718 /*
719  * Insert another buffer at dot.  Very useful.
720  */
721 /* ARGSUSED */
722 int
723 bufferinsert(int f, int n)
724 {
725         struct buffer *bp;
726         struct line   *clp;
727         int     clo, nline;
728         char    bufn[NBUFN], *bufp;
729
730         /* Get buffer to use from user */
731         if (curbp->b_altb != NULL)
732                 bufp = eread("Insert buffer: (default %s) ", bufn, NBUFN,
733                     EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname);
734         else
735                 bufp = eread("Insert buffer: ", bufn, NBUFN, EFNEW | EFBUF);
736         if (bufp == NULL)
737                 return (ABORT);
738         if (bufp[0] == '\0' && curbp->b_altb != NULL)
739                 bp = curbp->b_altb;
740         else if ((bp = bfind(bufn, FALSE)) == NULL)
741                 return (FALSE);
742
743         if (bp == curbp) {
744                 ewprintf("Cannot insert buffer into self");
745                 return (FALSE);
746         }
747         /* insert the buffer */
748         nline = 0;
749         clp = bfirstlp(bp);
750         for (;;) {
751                 for (clo = 0; clo < llength(clp); clo++)
752                         if (linsert(1, lgetc(clp, clo)) == FALSE)
753                                 return (FALSE);
754                 if ((clp = lforw(clp)) == bp->b_headp)
755                         break;
756                 if (newline(FFRAND, 1) == FALSE)        /* fake newline */
757                         return (FALSE);
758                 nline++;
759         }
760         if (nline == 1)
761                 ewprintf("[Inserted 1 line]");
762         else
763                 ewprintf("[Inserted %d lines]", nline);
764
765         clp = curwp->w_linep;           /* cosmetic adjustment  */
766         if (curwp->w_dotp == clp) {     /* for offscreen insert */
767                 while (nline-- && lback(clp) != curbp->b_headp)
768                         clp = lback(clp);
769                 curwp->w_linep = clp;   /* adjust framing.      */
770                 curwp->w_rflag |= WFFULL;
771         }
772         return (TRUE);
773 }
774
775 /*
776  * Turn off the dirty bit on this buffer.
777  */
778 /* ARGSUSED */
779 int
780 notmodified(int f, int n)
781 {
782         struct mgwin *wp;
783
784         curbp->b_flag &= ~BFCHG;
785         wp = wheadp;            /* Update mode lines.    */
786         while (wp != NULL) {
787                 if (wp->w_bufp == curbp)
788                         wp->w_rflag |= WFMODE;
789                 wp = wp->w_wndp;
790         }
791         ewprintf("Modification-flag cleared");
792         return (TRUE);
793 }
794
795 /*
796  * Popbuf and set all windows to top of buffer.
797  */
798 int
799 popbuftop(struct buffer *bp, int flags)
800 {
801         struct mgwin *wp;
802
803         bp->b_dotp = bfirstlp(bp);
804         bp->b_doto = 0;
805         if (bp->b_nwnd != 0) {
806                 for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
807                         if (wp->w_bufp == bp) {
808                                 wp->w_dotp = bp->b_dotp;
809                                 wp->w_doto = 0;
810                                 wp->w_rflag |= WFFULL;
811                         }
812         }
813         return (popbuf(bp, flags) != NULL);
814 }
815
816 /*
817  * Return the working directory for the current buffer, terminated
818  * with a '/'. First, try to extract it from the current buffer's
819  * filename. If that fails, use global cwd.
820  */
821 int
822 getbufcwd(char *path, size_t plen)
823 {
824         char cwd[NFILEN];
825
826         if (plen == 0)
827                 return (FALSE);
828
829         if (globalwd == FALSE && curbp->b_cwd[0] != '\0') {
830                 (void)strlcpy(path, curbp->b_cwd, plen);
831         } else {
832                 if (getcwdir(cwd, sizeof(cwd)) == FALSE)
833                         goto error;
834                 (void)strlcpy(path, cwd, plen);
835         }
836         return (TRUE);
837 error:
838         path[0] = '\0';
839         return (FALSE);
840 }
841
842 /*
843  * Ensures a buffer has not been modified elsewhere; e.g. on disk.
844  * Prompt the user if it has.
845  * Returns TRUE if it has NOT (i.e. buffer is ok to edit).
846  * FALSE or ABORT otherwise
847  */
848 int
849 checkdirty(struct buffer *bp)
850 {
851         int s;
852         
853         if ((bp->b_flag & (BFDIRTY | BFIGNDIRTY)) == BFDIRTY) {
854                 if ((s = eyorn("File changed on disk; really edit the buffer"))
855                     != TRUE)
856                         return (s);
857                 bp->b_flag &= ~BFDIRTY;
858                 bp->b_flag |= BFIGNDIRTY;
859         }
860
861         return (TRUE);
862 }
863