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