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 864