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