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