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