1 /* $OpenBSD: buffer.c,v 1.68 2008/09/15 16:11:35 kjell 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_flag |= WFMODE; 37 38 return (TRUE); 39 } 40 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 */ 47 /* ARGSUSED */ 48 int 49 usebuffer(int f, int n) 50 { 51 struct buffer *bp; 52 char bufn[NBUFN], *bufp; 53 54 /* Get buffer to use from user */ 55 if ((curbp->b_altb == NULL) && 56 ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL)) 57 bufp = eread("Switch to buffer: ", bufn, NBUFN, EFNEW | EFBUF); 58 else 59 bufp = eread("Switch to buffer: (default %s) ", bufn, NBUFN, 60 EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); 61 62 if (bufp == NULL) 63 return (ABORT); 64 if (bufp[0] == '\0' && curbp->b_altb != NULL) 65 bp = curbp->b_altb; 66 else if ((bp = bfind(bufn, TRUE)) == NULL) 67 return (FALSE); 68 69 /* and put it in current window */ 70 curbp = bp; 71 return (showbuffer(bp, curwp, WFFRAME | WFFULL)); 72 } 73 74 /* 75 * pop to buffer asked for by the user. 76 */ 77 /* ARGSUSED */ 78 int 79 poptobuffer(int f, int n) 80 { 81 struct buffer *bp; 82 struct mgwin *wp; 83 char bufn[NBUFN], *bufp; 84 85 /* Get buffer to use from user */ 86 if ((curbp->b_altb == NULL) && 87 ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL)) 88 bufp = eread("Switch to buffer in other window: ", bufn, NBUFN, 89 EFNEW | EFBUF); 90 else 91 bufp = eread("Switch to buffer in other window: (default %s) ", 92 bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); 93 if (bufp == NULL) 94 return (ABORT); 95 if (bufp[0] == '\0' && curbp->b_altb != NULL) 96 bp = curbp->b_altb; 97 else if ((bp = bfind(bufn, TRUE)) == NULL) 98 return (FALSE); 99 if (bp == curbp) 100 return (splitwind(f, n)); 101 /* and put it in a new window */ 102 if ((wp = popbuf(bp)) == NULL) 103 return (FALSE); 104 curbp = bp; 105 curwp = wp; 106 return (TRUE); 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 */ 116 /* ARGSUSED */ 117 int 118 killbuffer_cmd(int f, int n) 119 { 120 struct buffer *bp; 121 char bufn[NBUFN], *bufp; 122 123 if ((bufp = eread("Kill buffer: (default %s) ", bufn, NBUFN, 124 EFNUL | EFNEW | EFBUF, curbp->b_bname)) == NULL) 125 return (ABORT); 126 else if (bufp[0] == '\0') 127 bp = curbp; 128 else if ((bp = bfind(bufn, FALSE)) == NULL) 129 return (FALSE); 130 return (killbuffer(bp)); 131 } 132 133 int 134 killbuffer(struct buffer *bp) 135 { 136 struct buffer *bp1; 137 struct buffer *bp2; 138 struct mgwin *wp; 139 int s; 140 struct undo_rec *rec, *next; 141 142 /* 143 * Find some other buffer to display. Try the alternate buffer, 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... 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* */ 152 if (bp == bfind("*scratch*", FALSE)) 153 return (TRUE); 154 /* create *scratch* for alternate buffer */ 155 if ((bp1 = bfind("*scratch*", TRUE)) == NULL) 156 return (FALSE); 157 } 158 } 159 if ((s = bclear(bp)) != TRUE) 160 return (s); 161 for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) { 162 if (wp->w_bufp == bp) { 163 bp2 = bp1->b_altb; /* save alternate buffer */ 164 if (showbuffer(bp1, wp, WFMODE | WFFRAME | WFFULL)) 165 bp1->b_altb = bp2; 166 else 167 bp1 = bp2; 168 } 169 } 170 if (bp == curbp) 171 curbp = bp1; 172 free(bp->b_headp); /* Release header line. */ 173 bp2 = NULL; /* Find the header. */ 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 } 181 bp1 = bp1->b_bufp; /* Next one in chain. */ 182 if (bp2 == NULL) /* Unlink it. */ 183 bheadp = bp1; 184 else 185 bp2->b_bufp = bp1; 186 while (bp1 != NULL) { /* Finish with altb's */ 187 if (bp1->b_altb == bp) 188 bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb; 189 bp1 = bp1->b_bufp; 190 } 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 198 free(bp->b_bname); /* Release name block */ 199 free(bp); /* Release buffer block */ 200 return (TRUE); 201 } 202 203 /* 204 * Save some buffers - just call anycb with the arg flag. 205 */ 206 /* ARGSUSED */ 207 int 208 savebuffers(int f, int n) 209 { 210 if (anycb(f) == ABORT) 211 return (ABORT); 212 return (TRUE); 213 } 214 215 /* 216 * Listing buffers. 217 */ 218 static int listbuf_ncol; 219 220 static int listbuf_goto_buffer(int f, int n); 221 static int listbuf_goto_buffer_one(int f, int n); 222 static int listbuf_goto_buffer_helper(int f, int n, int only); 223 224 static PF listbuf_pf[] = { 225 listbuf_goto_buffer 226 }; 227 static PF listbuf_one[] = { 228 listbuf_goto_buffer_one 229 }; 230 231 232 static struct KEYMAPE (2 + IMAPEXT) listbufmap = { 233 2, 234 2 + IMAPEXT, 235 rescan, 236 { 237 { 238 CCHR('M'), CCHR('M'), listbuf_pf, NULL 239 }, 240 { 241 '1', '1', listbuf_one, NULL 242 } 243 } 244 }; 245 246 /* 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 */ 253 /* ARGSUSED */ 254 int 255 listbuffers(int f, int n) 256 { 257 static int initialized = 0; 258 struct buffer *bp; 259 struct mgwin *wp; 260 261 if (!initialized) { 262 maps_add((KEYMAP *)&listbufmap, "listbufmap"); 263 initialized = 1; 264 } 265 266 if ((bp = makelist()) == NULL || (wp = popbuf(bp)) == NULL) 267 return (FALSE); 268 wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */ 269 wp->w_doto = bp->b_doto; 270 bp->b_modes[0] = name_mode("fundamental"); 271 bp->b_modes[1] = name_mode("listbufmap"); 272 bp->b_nmodes = 1; 273 274 return (TRUE); 275 } 276 277 /* 278 * This routine rebuilds the text for the 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). 283 */ 284 static struct buffer * 285 makelist(void) 286 { 287 int w = ncol / 2; 288 struct buffer *bp, *blp; 289 struct line *lp; 290 291 if ((blp = bfind("*Buffer List*", TRUE)) == NULL) 292 return (NULL); 293 if (bclear(blp) != TRUE) 294 return (NULL); 295 blp->b_flag &= ~BFCHG; /* Blow away old. */ 296 blp->b_flag |= BFREADONLY; 297 298 listbuf_ncol = ncol; /* cache ncol for listbuf_goto_buffer */ 299 300 if (addlinef(blp, "%-*s%s", w, " MR Buffer", "Size File") == FALSE || 301 addlinef(blp, "%-*s%s", w, " -- ------", "---- ----") == FALSE) 302 return (NULL); 303 304 for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { 305 RSIZE nbytes; 306 307 nbytes = 0; /* Count bytes in buf. */ 308 if (bp != blp) { 309 lp = bfirstlp(bp); 310 while (lp != bp->b_headp) { 311 nbytes += llength(lp) + 1; 312 lp = lforw(lp); 313 } 314 if (nbytes) 315 nbytes--; /* no bonus newline */ 316 } 317 318 if (addlinef(blp, "%c%c%c %-*.*s%c%-6d %-*s", 319 (bp == curbp) ? '.' : ' ', /* current buffer ? */ 320 ((bp->b_flag & BFCHG) != 0) ? '*' : ' ', /* changed ? */ 321 ((bp->b_flag & BFREADONLY) != 0) ? ' ' : '*', 322 w - 5, /* four chars already written */ 323 w - 5, /* four chars already written */ 324 bp->b_bname, /* buffer name */ 325 strlen(bp->b_bname) < w - 5 ? ' ' : '$', /* truncated? */ 326 nbytes, /* buffer size */ 327 w - 7, /* seven chars already written */ 328 bp->b_fname) == FALSE) 329 return (NULL); 330 } 331 blp->b_dotp = bfirstlp(blp); /* put dot at beginning of 332 * buffer */ 333 blp->b_doto = 0; 334 return (blp); /* All done */ 335 } 336 337 static int 338 listbuf_goto_buffer(int f, int n) 339 { 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 { 352 struct buffer *bp; 353 struct mgwin *wp; 354 char *line = NULL; 355 int i, ret = FALSE; 356 357 if (curwp->w_dotp->l_text[listbuf_ncol/2 - 1] == '$') { 358 ewprintf("buffer name truncated"); 359 return (FALSE); 360 } 361 362 if ((line = malloc(listbuf_ncol/2)) == NULL) 363 return (FALSE); 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 } 372 if (i == 0) 373 goto cleanup; 374 375 for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { 376 if (strcmp(bp->b_bname, line) == 0) 377 break; 378 } 379 if (bp == NULL) 380 goto cleanup; 381 382 if ((wp = popbuf(bp)) == NULL) 383 goto cleanup; 384 curbp = bp; 385 curwp = wp; 386 387 if (only) 388 ret = (onlywind(f, n)); 389 else 390 ret = TRUE; 391 392 cleanup: 393 free(line); 394 395 return (ret); 396 } 397 398 /* 399 * The argument "fmt" points to a format string. Append this line to the 400 * buffer. Handcraft the EOL on the end. Return TRUE if it worked and 401 * FALSE if you ran out of room. 402 */ 403 int 404 addlinef(struct buffer *bp, char *fmt, ...) 405 { 406 va_list ap; 407 struct line *lp; 408 409 if ((lp = lalloc(0)) == NULL) 410 return (FALSE); 411 va_start(ap, fmt); 412 if (vasprintf(&lp->l_text, fmt, ap) == -1) { 413 lfree(lp); 414 va_end(ap); 415 return (FALSE); 416 } 417 lp->l_used = strlen(lp->l_text); 418 va_end(ap); 419 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; 424 bp->b_lines++; 425 426 return (TRUE); 427 } 428 429 /* 430 * Look through the list of buffers, giving the user a chance to save them. 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. 434 */ 435 int 436 anycb(int f) 437 { 438 struct buffer *bp; 439 int s = FALSE, save = FALSE, ret; 440 char pbuf[NFILEN + 11]; 441 442 for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { 443 if (bp->b_fname != NULL && *(bp->b_fname) != '\0' && 444 (bp->b_flag & BFCHG) != 0) { 445 ret = snprintf(pbuf, sizeof(pbuf), "Save file %s", 446 bp->b_fname); 447 if (ret < 0 || ret >= sizeof(pbuf)) { 448 ewprintf("Error: filename too long!"); 449 return (ABORT); 450 } 451 if ((f == TRUE || (save = eyorn(pbuf)) == TRUE) && 452 buffsave(bp) == TRUE) { 453 bp->b_flag &= ~BFCHG; 454 upmodes(bp); 455 } else 456 s = TRUE; 457 if (save == ABORT) 458 return (save); 459 save = TRUE; 460 } 461 } 462 if (save == FALSE /* && kbdmop == NULL */ ) /* experimental */ 463 ewprintf("(No files need saving)"); 464 return (s); 465 } 466 467 /* 468 * Search for a buffer, by name. 469 * If not found, and the "cflag" is TRUE, 470 * create a new buffer. Return pointer to the found 471 * (or new) buffer. 472 */ 473 struct buffer * 474 bfind(const char *bname, int cflag) 475 { 476 struct buffer *bp; 477 478 bp = bheadp; 479 while (bp != NULL) { 480 if (strcmp(bname, bp->b_bname) == 0) 481 return (bp); 482 bp = bp->b_bufp; 483 } 484 if (cflag != TRUE) 485 return (NULL); 486 487 bp = bnew(bname); 488 489 return (bp); 490 } 491 492 /* 493 * Create a new buffer and put it in the list of 494 * all buffers. 495 */ 496 static struct buffer * 497 bnew(const char *bname) 498 { 499 struct buffer *bp; 500 struct line *lp; 501 int i; 502 503 bp = calloc(1, sizeof(struct buffer)); 504 if (bp == NULL) { 505 ewprintf("Can't get %d bytes", sizeof(struct buffer)); 506 return (NULL); 507 } 508 if ((lp = lalloc(0)) == NULL) { 509 free(bp); 510 return (NULL); 511 } 512 bp->b_altb = bp->b_bufp = NULL; 513 bp->b_dotp = lp; 514 bp->b_doto = 0; 515 bp->b_markp = NULL; 516 bp->b_marko = 0; 517 bp->b_flag = defb_flag; 518 bp->b_nwnd = 0; 519 bp->b_headp = lp; 520 bp->b_nmodes = defb_nmodes; 521 LIST_INIT(&bp->b_undo); 522 bp->b_undoptr = NULL; 523 memset(&bp->b_undopos, 0, sizeof(bp->b_undopos)); 524 i = 0; 525 do { 526 bp->b_modes[i] = defb_modes[i]; 527 } while (i++ < defb_nmodes); 528 bp->b_fname[0] = '\0'; 529 bp->b_cwd[0] = '\0'; 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; 535 bp->b_dotline = bp->b_markline = 1; 536 bp->b_lines = 1; 537 if ((bp->b_bname = strdup(bname)) == NULL) { 538 ewprintf("Can't get %d bytes", strlen(bname) + 1); 539 return (NULL); 540 } 541 542 return (bp); 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 */ 555 int 556 bclear(struct buffer *bp) 557 { 558 struct line *lp; 559 int s; 560 561 if ((bp->b_flag & BFCHG) != 0 && /* Changed. */ 562 (s = eyesno("Buffer modified; kill anyway")) != TRUE) 563 return (s); 564 bp->b_flag &= ~BFCHG; /* Not changed */ 565 while ((lp = lforw(bp->b_headp)) != bp->b_headp) 566 lfree(lp); 567 bp->b_dotp = bp->b_headp; /* Fix dot */ 568 bp->b_doto = 0; 569 bp->b_markp = NULL; /* Invalidate "mark" */ 570 bp->b_marko = 0; 571 bp->b_dotline = bp->b_markline = 1; 572 bp->b_lines = 1; 573 574 return (TRUE); 575 } 576 577 /* 578 * Display the given buffer in the given window. Flags indicated 579 * action on redisplay. Update modified flag so insert loop can check it. 580 */ 581 int 582 showbuffer(struct buffer *bp, struct mgwin *wp, int flags) 583 { 584 struct buffer *obp; 585 struct mgwin *owp; 586 587 /* Ensure file has not been modified elsewhere */ 588 if (fchecktime(bp) != TRUE) 589 bp->b_flag |= BFDIRTY; 590 591 if (wp->w_bufp == bp) { /* Easy case! */ 592 wp->w_flag |= flags; 593 wp->w_dotp = bp->b_dotp; 594 wp->w_doto = bp->b_doto; 595 return (TRUE); 596 } 597 /* First, detach the old buffer from the window */ 598 if ((bp->b_altb = obp = wp->w_bufp) != NULL) { 599 if (--obp->b_nwnd == 0) { 600 obp->b_dotp = wp->w_dotp; 601 obp->b_doto = wp->w_doto; 602 obp->b_markp = wp->w_markp; 603 obp->b_marko = wp->w_marko; 604 obp->b_dotline = wp->w_dotline; 605 obp->b_markline = wp->w_markline; 606 } 607 } 608 /* Now, attach the new buffer to the window */ 609 wp->w_bufp = bp; 610 611 if (bp->b_nwnd++ == 0) { /* First use. */ 612 wp->w_dotp = bp->b_dotp; 613 wp->w_doto = bp->b_doto; 614 wp->w_markp = bp->b_markp; 615 wp->w_marko = bp->b_marko; 616 wp->w_dotline = bp->b_dotline; 617 wp->w_markline = bp->b_markline; 618 } else 619 /* already on screen, steal values from other window */ 620 for (owp = wheadp; owp != NULL; owp = wp->w_wndp) 621 if (wp->w_bufp == bp && owp != wp) { 622 wp->w_dotp = owp->w_dotp; 623 wp->w_doto = owp->w_doto; 624 wp->w_markp = owp->w_markp; 625 wp->w_marko = owp->w_marko; 626 wp->w_dotline = owp->w_dotline; 627 wp->w_markline = owp->w_markline; 628 break; 629 } 630 wp->w_flag |= WFMODE | flags; 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 643 augbname(char *bn, const char *fn, size_t bs) 644 { 645 int count; 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 656 return (TRUE); 657 } 658 659 /* 660 * Pop the buffer we got passed onto the screen. 661 * Returns a status. 662 */ 663 struct mgwin * 664 popbuf(struct buffer *bp) 665 { 666 struct mgwin *wp; 667 668 if (bp->b_nwnd == 0) { /* Not on screen yet. */ 669 if ((wp = wpopup()) == NULL) 670 return (NULL); 671 } else 672 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) 673 if (wp->w_bufp == bp) { 674 wp->w_flag |= WFFULL | WFFRAME; 675 return (wp); 676 } 677 if (showbuffer(bp, wp, WFFULL) != TRUE) 678 return (NULL); 679 return (wp); 680 } 681 682 /* 683 * Insert another buffer at dot. Very useful. 684 */ 685 /* ARGSUSED */ 686 int 687 bufferinsert(int f, int n) 688 { 689 struct buffer *bp; 690 struct line *clp; 691 int clo, nline; 692 char bufn[NBUFN], *bufp; 693 694 /* Get buffer to use from user */ 695 if (curbp->b_altb != NULL) 696 bufp = eread("Insert buffer: (default %s) ", bufn, NBUFN, 697 EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); 698 else 699 bufp = eread("Insert buffer: ", bufn, NBUFN, EFNEW | EFBUF); 700 if (bufp == NULL) 701 return (ABORT); 702 if (bufp[0] == '\0' && curbp->b_altb != NULL) 703 bp = curbp->b_altb; 704 else if ((bp = bfind(bufn, FALSE)) == NULL) 705 return (FALSE); 706 707 if (bp == curbp) { 708 ewprintf("Cannot insert buffer into self"); 709 return (FALSE); 710 } 711 /* insert the buffer */ 712 nline = 0; 713 clp = bfirstlp(bp); 714 for (;;) { 715 for (clo = 0; clo < llength(clp); clo++) 716 if (linsert(1, lgetc(clp, clo)) == FALSE) 717 return (FALSE); 718 if ((clp = lforw(clp)) == bp->b_headp) 719 break; 720 if (newline(FFRAND, 1) == FALSE) /* fake newline */ 721 return (FALSE); 722 nline++; 723 } 724 if (nline == 1) 725 ewprintf("[Inserted 1 line]"); 726 else 727 ewprintf("[Inserted %d lines]", nline); 728 729 clp = curwp->w_linep; /* cosmetic adjustment */ 730 if (curwp->w_dotp == clp) { /* for offscreen insert */ 731 while (nline-- && lback(clp) != curbp->b_headp) 732 clp = lback(clp); 733 curwp->w_linep = clp; /* adjust framing. */ 734 curwp->w_flag |= WFFULL; 735 } 736 return (TRUE); 737 } 738 739 /* 740 * Turn off the dirty bit on this buffer. 741 */ 742 /* ARGSUSED */ 743 int 744 notmodified(int f, int n) 745 { 746 struct mgwin *wp; 747 748 curbp->b_flag &= ~BFCHG; 749 wp = wheadp; /* Update mode lines. */ 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"); 756 return (TRUE); 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 */ 764 int 765 popbuftop(struct buffer *bp) 766 { 767 struct mgwin *wp; 768 769 bp->b_dotp = bfirstlp(bp); 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; 776 wp->w_flag |= WFFULL; 777 } 778 } 779 return (popbuf(bp) != NULL); 780 } 781 #endif 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 796 if (globalwd == FALSE && curbp->b_cwd[0] != '\0') { 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 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 829