Annotation of src/usr.bin/vim/buffer.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2: /* vi:set ts=4 sw=4:
! 3: *
! 4: * VIM - Vi IMproved by Bram Moolenaar
! 5: *
! 6: * Do ":help uganda" in Vim to read copying and usage conditions.
! 7: * Do ":help credits" in Vim to see a list of people who contributed.
! 8: */
! 9:
! 10: /*
! 11: * buffer.c: functions for dealing with the buffer structure
! 12: */
! 13:
! 14: /*
! 15: * The buffer list is a double linked list of all buffers.
! 16: * Each buffer can be in one of these states:
! 17: * never loaded: b_neverloaded == TRUE, only the file name is valid
! 18: * not loaded: b_ml.ml_mfp == NULL, no memfile allocated
! 19: * hidden: b_nwindows == 0, loaded but not displayed in a window
! 20: * normal: loaded and displayed in a window
! 21: *
! 22: * Instead of storing file names all over the place, each file name is
! 23: * stored in the buffer list. It can be referenced by a number.
! 24: *
! 25: * The current implementation remembers all file names ever used.
! 26: */
! 27:
! 28: #include "vim.h"
! 29: #include "globals.h"
! 30: #include "proto.h"
! 31: #include "option.h"
! 32:
! 33: static void enter_buffer __ARGS((BUF *));
! 34: static void free_buf_options __ARGS((BUF *));
! 35: static char_u *buflist_match __ARGS((regexp *prog, BUF *buf));
! 36: static void buflist_setlnum __ARGS((BUF *, linenr_t));
! 37: static linenr_t buflist_findlnum __ARGS((BUF *));
! 38: static void append_arg_number __ARGS((char_u *, int));
! 39:
! 40: /*
! 41: * Open current buffer, that is: open the memfile and read the file into memory
! 42: * return FAIL for failure, OK otherwise
! 43: */
! 44: int
! 45: open_buffer()
! 46: {
! 47: int retval = OK;
! 48:
! 49: /*
! 50: * The 'readonly' flag is only set when b_neverloaded is being reset.
! 51: * When re-entering the same buffer, it should not change, because the
! 52: * user may have reset the flag by hand.
! 53: */
! 54: if (readonlymode && curbuf->b_filename != NULL && curbuf->b_neverloaded)
! 55: curbuf->b_p_ro = TRUE;
! 56:
! 57: if (ml_open() == FAIL)
! 58: {
! 59: /*
! 60: * There MUST be a memfile, otherwise we can't do anything
! 61: * If we can't create one for the current buffer, take another buffer
! 62: */
! 63: close_buffer(NULL, curbuf, FALSE, FALSE);
! 64: for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
! 65: if (curbuf->b_ml.ml_mfp != NULL)
! 66: break;
! 67: /*
! 68: * if there is no memfile at all, exit
! 69: * This is OK, since there are no changes to loose.
! 70: */
! 71: if (curbuf == NULL)
! 72: {
! 73: EMSG("Cannot allocate buffer, exiting...");
! 74: getout(2);
! 75: }
! 76: EMSG("Cannot allocate buffer, using other one...");
! 77: enter_buffer(curbuf);
! 78: return FAIL;
! 79: }
! 80: if (curbuf->b_filename != NULL)
! 81: retval = readfile(curbuf->b_filename, curbuf->b_sfilename,
! 82: (linenr_t)0, TRUE, (linenr_t)0, MAXLNUM, FALSE);
! 83: else
! 84: {
! 85: MSG("Empty Buffer");
! 86: msg_col = 0;
! 87: msg_didout = FALSE; /* overwrite this message whenever you like */
! 88: }
! 89:
! 90: /* if first time loading this buffer, init chartab */
! 91: if (curbuf->b_neverloaded)
! 92: init_chartab();
! 93:
! 94: /*
! 95: * Reset the Changed flag first, autocmds may change the buffer.
! 96: * Apply the automatic commands, before processing the modelines.
! 97: * So the modelines have priority over auto commands.
! 98: */
! 99: if (retval != FAIL)
! 100: UNCHANGED(curbuf);
! 101:
! 102: #ifdef AUTOCMD
! 103: apply_autocmds(EVENT_BUFENTER, NULL, NULL);
! 104: #endif
! 105:
! 106: if (retval != FAIL)
! 107: {
! 108: do_modelines();
! 109: curbuf->b_neverloaded = FALSE;
! 110: }
! 111:
! 112: return retval;
! 113: }
! 114:
! 115: /*
! 116: * Close the link to a buffer. If "free_buf" is TRUE free the buffer if it
! 117: * becomes unreferenced. The caller should get a new buffer very soon!
! 118: * if 'del_buf' is TRUE, remove the buffer from the buffer list.
! 119: */
! 120: void
! 121: close_buffer(win, buf, free_buf, del_buf)
! 122: WIN *win; /* if not NULL, set b_last_cursor */
! 123: BUF *buf;
! 124: int free_buf;
! 125: int del_buf;
! 126: {
! 127: if (buf->b_nwindows > 0)
! 128: --buf->b_nwindows;
! 129: if (buf->b_nwindows == 0 && win != NULL)
! 130: set_last_cursor(win); /* may set b_last_cursor */
! 131: if (buf->b_nwindows > 0 || !free_buf)
! 132: {
! 133: if (buf == curbuf)
! 134: u_sync(); /* sync undo before going to another buffer */
! 135: return;
! 136: }
! 137:
! 138: buf_freeall(buf); /* free all things allocated for this buffer */
! 139: /*
! 140: * If there is no file name, remove the buffer from the list
! 141: */
! 142: if (buf->b_filename == NULL || del_buf)
! 143: {
! 144: vim_free(buf->b_filename);
! 145: vim_free(buf->b_sfilename);
! 146: if (buf->b_prev == NULL)
! 147: firstbuf = buf->b_next;
! 148: else
! 149: buf->b_prev->b_next = buf->b_next;
! 150: if (buf->b_next == NULL)
! 151: lastbuf = buf->b_prev;
! 152: else
! 153: buf->b_next->b_prev = buf->b_prev;
! 154: free_buf_options(buf);
! 155: }
! 156: else
! 157: buf_clear(buf);
! 158: }
! 159:
! 160: /*
! 161: * buf_clear() - make buffer empty
! 162: */
! 163: void
! 164: buf_clear(buf)
! 165: BUF *buf;
! 166: {
! 167: buf->b_ml.ml_line_count = 1;
! 168: buf->b_changed = FALSE;
! 169: #ifndef SHORT_FNAME
! 170: buf->b_shortname = FALSE;
! 171: #endif
! 172: buf->b_p_eol = TRUE;
! 173: buf->b_ml.ml_mfp = NULL;
! 174: buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */
! 175: }
! 176:
! 177: /*
! 178: * buf_freeall() - free all things allocated for the buffer
! 179: */
! 180: void
! 181: buf_freeall(buf)
! 182: BUF *buf;
! 183: {
! 184: u_blockfree(buf); /* free the memory allocated for undo */
! 185: ml_close(buf, TRUE); /* close and delete the memline/memfile */
! 186: buf->b_ml.ml_line_count = 0; /* no lines in buffer */
! 187: u_clearall(buf); /* reset all undo information */
! 188: }
! 189:
! 190: /*
! 191: * do_bufdel() - delete or unload buffer(s)
! 192: *
! 193: * addr_count == 0: ":bdel" - delete current buffer
! 194: * addr_count == 1: ":N bdel" or ":bdel N [N ..] - first delete
! 195: * buffer "end_bnr", then any other arguments.
! 196: * addr_count == 2: ":N,N bdel" - delete buffers in range
! 197: *
! 198: * command can be DOBUF_UNLOAD (":bunload") or DOBUF_DEL (":bdel")
! 199: *
! 200: * Returns error message or NULL
! 201: */
! 202: char_u *
! 203: do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit)
! 204: int command;
! 205: char_u *arg; /* pointer to extra arguments */
! 206: int addr_count;
! 207: int start_bnr; /* first buffer number in a range */
! 208: int end_bnr; /* buffer number or last buffer number in a range */
! 209: int forceit;
! 210: {
! 211: int do_current = 0; /* delete current buffer? */
! 212: int deleted = 0; /* number of buffers deleted */
! 213: char_u *errormsg = NULL; /* return value */
! 214: int bnr; /* buffer number */
! 215: char_u *p;
! 216:
! 217: if (addr_count == 0)
! 218: (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
! 219: else
! 220: {
! 221: if (addr_count == 2)
! 222: {
! 223: if (*arg) /* both range and argument is not allowed */
! 224: return e_trailing;
! 225: bnr = start_bnr;
! 226: }
! 227: else /* addr_count == 1 */
! 228: bnr = end_bnr;
! 229:
! 230: for ( ;!got_int; mch_breakcheck())
! 231: {
! 232: /*
! 233: * delete the current buffer last, otherwise when the
! 234: * current buffer is deleted, the next buffer becomes
! 235: * the current one and will be loaded, which may then
! 236: * also be deleted, etc.
! 237: */
! 238: if (bnr == curbuf->b_fnum)
! 239: do_current = bnr;
! 240: else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
! 241: forceit) == OK)
! 242: ++deleted;
! 243:
! 244: /*
! 245: * find next buffer number to delete/unload
! 246: */
! 247: if (addr_count == 2)
! 248: {
! 249: if (++bnr > end_bnr)
! 250: break;
! 251: }
! 252: else /* addr_count == 1 */
! 253: {
! 254: arg = skipwhite(arg);
! 255: if (*arg == NUL)
! 256: break;
! 257: if (!isdigit(*arg))
! 258: {
! 259: p = skiptowhite_esc(arg);
! 260: bnr = buflist_findpat(arg, p);
! 261: if (bnr < 0) /* failed */
! 262: break;
! 263: arg = p;
! 264: }
! 265: else
! 266: bnr = getdigits(&arg);
! 267: }
! 268: }
! 269: if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
! 270: FORWARD, do_current, forceit) == OK)
! 271: ++deleted;
! 272:
! 273: if (deleted == 0)
! 274: {
! 275: sprintf((char *)IObuff, "No buffers were %s",
! 276: command == DOBUF_UNLOAD ? "unloaded" : "deleted");
! 277: errormsg = IObuff;
! 278: }
! 279: else
! 280: smsg((char_u *)"%d buffer%s %s", deleted,
! 281: plural((long)deleted),
! 282: command == DOBUF_UNLOAD ? "unloaded" : "deleted");
! 283: }
! 284:
! 285: return errormsg;
! 286: }
! 287:
! 288: /*
! 289: * Implementation of the command for the buffer list
! 290: *
! 291: * action == DOBUF_GOTO go to specified buffer
! 292: * action == DOBUF_SPLIT split window and go to specified buffer
! 293: * action == DOBUF_UNLOAD unload specified buffer(s)
! 294: * action == DOBUF_DEL delete specified buffer(s)
! 295: *
! 296: * start == DOBUF_CURRENT go to "count" buffer from current buffer
! 297: * start == DOBUF_FIRST go to "count" buffer from first buffer
! 298: * start == DOBUF_LAST go to "count" buffer from last buffer
! 299: * start == DOBUF_MOD go to "count" modified buffer from current buffer
! 300: *
! 301: * Return FAIL or OK.
! 302: */
! 303: int
! 304: do_buffer(action, start, dir, count, forceit)
! 305: int action;
! 306: int start;
! 307: int dir; /* FORWARD or BACKWARD */
! 308: int count; /* buffer number or number of buffers */
! 309: int forceit; /* TRUE for :bdelete! */
! 310: {
! 311: BUF *buf;
! 312: BUF *delbuf;
! 313: int retval;
! 314:
! 315: switch (start)
! 316: {
! 317: case DOBUF_FIRST: buf = firstbuf; break;
! 318: case DOBUF_LAST: buf = lastbuf; break;
! 319: default: buf = curbuf; break;
! 320: }
! 321: if (start == DOBUF_MOD) /* find next modified buffer */
! 322: {
! 323: while (count-- > 0)
! 324: {
! 325: do
! 326: {
! 327: buf = buf->b_next;
! 328: if (buf == NULL)
! 329: buf = firstbuf;
! 330: }
! 331: while (buf != curbuf && !buf->b_changed);
! 332: }
! 333: if (!buf->b_changed)
! 334: {
! 335: EMSG("No modified buffer found");
! 336: return FAIL;
! 337: }
! 338: }
! 339: else if (start == DOBUF_FIRST && count) /* find specified buffer number */
! 340: {
! 341: while (buf != NULL && buf->b_fnum != count)
! 342: buf = buf->b_next;
! 343: }
! 344: else
! 345: {
! 346: while (count-- > 0)
! 347: {
! 348: if (dir == FORWARD)
! 349: {
! 350: buf = buf->b_next;
! 351: if (buf == NULL)
! 352: buf = firstbuf;
! 353: }
! 354: else
! 355: {
! 356: buf = buf->b_prev;
! 357: if (buf == NULL)
! 358: buf = lastbuf;
! 359: }
! 360: }
! 361: }
! 362:
! 363: if (buf == NULL) /* could not find it */
! 364: {
! 365: if (start == DOBUF_FIRST)
! 366: {
! 367: /* don't warn when deleting */
! 368: if (action != DOBUF_UNLOAD && action != DOBUF_DEL)
! 369: EMSGN("Cannot go to buffer %ld", count);
! 370: }
! 371: else if (dir == FORWARD)
! 372: EMSG("Cannot go beyond last buffer");
! 373: else
! 374: EMSG("Cannot go before first buffer");
! 375: return FAIL;
! 376: }
! 377:
! 378: /*
! 379: * delete buffer buf from memory and/or the list
! 380: */
! 381: if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
! 382: {
! 383: if (!forceit && buf->b_changed)
! 384: {
! 385: EMSGN("No write since last change for buffer %ld (use ! to override)",
! 386: buf->b_fnum);
! 387: return FAIL;
! 388: }
! 389:
! 390: /*
! 391: * If deleting last buffer, make it empty.
! 392: * The last buffer cannot be unloaded.
! 393: */
! 394: if (firstbuf->b_next == NULL)
! 395: {
! 396: if (action == DOBUF_UNLOAD)
! 397: {
! 398: EMSG("Cannot unload last buffer");
! 399: return FAIL;
! 400: }
! 401: /* Close any other windows on this buffer */
! 402: close_others(FALSE);
! 403: buf = curbuf;
! 404: setpcmark();
! 405: retval = do_ecmd(0, NULL, NULL, NULL, FALSE, (linenr_t)1, FALSE);
! 406: /*
! 407: * The do_ecmd() may create a new buffer, then we have to delete
! 408: * the old one. But do_ecmd() may have done that already, check
! 409: * if the buffer still exists (it will be the first or second in
! 410: * the buffer list).
! 411: */
! 412: if (buf != curbuf && (buf == firstbuf || buf == firstbuf->b_next))
! 413: close_buffer(NULL, buf, TRUE, TRUE);
! 414: return retval;
! 415: }
! 416:
! 417: /*
! 418: * If the deleted buffer is the current one, close the current window
! 419: * (unless it's the only window).
! 420: */
! 421: while (buf == curbuf && firstwin != lastwin)
! 422: close_window(curwin, FALSE);
! 423:
! 424: /*
! 425: * If the buffer to be deleted is not current one, delete it here.
! 426: */
! 427: if (buf != curbuf)
! 428: {
! 429: close_windows(buf);
! 430: close_buffer(NULL, buf, TRUE, action == DOBUF_DEL);
! 431: return OK;
! 432: }
! 433:
! 434: /*
! 435: * Deleting the current buffer: Need to find another buffer to go to.
! 436: * There must be another, otherwise it would have been handled above.
! 437: */
! 438: if (curbuf->b_next != NULL)
! 439: buf = curbuf->b_next;
! 440: else
! 441: buf = curbuf->b_prev;
! 442: }
! 443:
! 444: /*
! 445: * make buf current buffer
! 446: */
! 447: setpcmark();
! 448: if (action == DOBUF_SPLIT) /* split window first */
! 449: {
! 450: if (win_split(0, FALSE) == FAIL)
! 451: return FAIL;
! 452: }
! 453: curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
! 454: buflist_altlnum(); /* remember curpos.lnum */
! 455:
! 456: #ifdef AUTOCMD
! 457: apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
! 458: #endif
! 459: delbuf = curbuf; /* close_windows() may change curbuf */
! 460: if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
! 461: close_windows(curbuf);
! 462: close_buffer(NULL, delbuf, action == DOBUF_UNLOAD || action == DOBUF_DEL,
! 463: action == DOBUF_DEL);
! 464: enter_buffer(buf);
! 465: return OK;
! 466: }
! 467:
! 468: /*
! 469: * enter a new current buffer.
! 470: * (old curbuf must have been freed already)
! 471: */
! 472: static void
! 473: enter_buffer(buf)
! 474: BUF *buf;
! 475: {
! 476: buf_copy_options(curbuf, buf, TRUE);
! 477: curwin->w_buffer = buf;
! 478: curbuf = buf;
! 479: ++curbuf->b_nwindows;
! 480: if (curbuf->b_ml.ml_mfp == NULL) /* need to load the file */
! 481: open_buffer();
! 482: else
! 483: {
! 484: need_fileinfo = TRUE; /* display file info after redraw */
! 485: buf_check_timestamp(curbuf); /* check if file has changed */
! 486: #ifdef AUTOCMD
! 487: apply_autocmds(EVENT_BUFENTER, NULL, NULL);
! 488: #endif
! 489: }
! 490: buflist_getlnum(); /* restore curpos.lnum */
! 491: check_arg_idx(); /* check for valid arg_idx */
! 492: maketitle();
! 493: scroll_cursor_halfway(FALSE); /* redisplay at correct position */
! 494: updateScreen(NOT_VALID);
! 495: }
! 496:
! 497: /*
! 498: * functions for dealing with the buffer list
! 499: */
! 500:
! 501: /*
! 502: * Add a file name to the buffer list. Return a pointer to the buffer.
! 503: * If the same file name already exists return a pointer to that buffer.
! 504: * If it does not exist, or if fname == NULL, a new entry is created.
! 505: * If use_curbuf is TRUE, may use current buffer.
! 506: * This is the ONLY way to create a new buffer.
! 507: */
! 508: BUF *
! 509: buflist_new(fname, sfname, lnum, use_curbuf)
! 510: char_u *fname;
! 511: char_u *sfname;
! 512: linenr_t lnum;
! 513: int use_curbuf;
! 514: {
! 515: static int top_file_num = 1; /* highest file number */
! 516: BUF *buf;
! 517:
! 518: fname_expand(&fname, &sfname);
! 519:
! 520: /*
! 521: * If file name already exists in the list, update the entry
! 522: */
! 523: if (fname != NULL && (buf = buflist_findname(fname)) != NULL)
! 524: {
! 525: if (lnum != 0)
! 526: buflist_setlnum(buf, lnum);
! 527: /* copy the options now, if 'cpo' doesn't have 's' and not done
! 528: * already */
! 529: buf_copy_options(curbuf, buf, FALSE);
! 530: return buf;
! 531: }
! 532:
! 533: /*
! 534: * If the current buffer has no name and no contents, use the current buffer.
! 535: * Otherwise: Need to allocate a new buffer structure.
! 536: *
! 537: * This is the ONLY place where a new buffer structure is allocated!
! 538: */
! 539: if (use_curbuf && curbuf != NULL && curbuf->b_filename == NULL &&
! 540: curbuf->b_nwindows <= 1 &&
! 541: (curbuf->b_ml.ml_mfp == NULL || bufempty()))
! 542: buf = curbuf;
! 543: else
! 544: {
! 545: buf = (BUF *)alloc((unsigned)sizeof(BUF));
! 546: if (buf == NULL)
! 547: return NULL;
! 548: (void)vim_memset(buf, 0, sizeof(BUF));
! 549: }
! 550:
! 551: if (fname != NULL)
! 552: {
! 553: buf->b_filename = strsave(fname);
! 554: buf->b_sfilename = strsave(sfname);
! 555: }
! 556: if (buf->b_winlnum == NULL)
! 557: buf->b_winlnum = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
! 558: if ((fname != NULL && (buf->b_filename == NULL ||
! 559: buf->b_sfilename == NULL)) || buf->b_winlnum == NULL)
! 560: {
! 561: vim_free(buf->b_filename);
! 562: buf->b_filename = NULL;
! 563: vim_free(buf->b_sfilename);
! 564: buf->b_sfilename = NULL;
! 565: if (buf != curbuf)
! 566: {
! 567: vim_free(buf->b_winlnum);
! 568: free_buf_options(buf);
! 569: }
! 570: return NULL;
! 571: }
! 572:
! 573: if (buf == curbuf)
! 574: {
! 575: buf_freeall(buf); /* free all things allocated for this buffer */
! 576: buf->b_nwindows = 0;
! 577: }
! 578: else
! 579: {
! 580: /*
! 581: * Copy the options from the current buffer.
! 582: */
! 583: buf_copy_options(curbuf, buf, FALSE);
! 584:
! 585: /*
! 586: * put new buffer at the end of the buffer list
! 587: */
! 588: buf->b_next = NULL;
! 589: if (firstbuf == NULL) /* buffer list is empty */
! 590: {
! 591: buf->b_prev = NULL;
! 592: firstbuf = buf;
! 593: }
! 594: else /* append new buffer at end of list */
! 595: {
! 596: lastbuf->b_next = buf;
! 597: buf->b_prev = lastbuf;
! 598: }
! 599: lastbuf = buf;
! 600:
! 601: buf->b_fnum = top_file_num++;
! 602: if (top_file_num < 0) /* wrap around (may cause duplicates) */
! 603: {
! 604: EMSG("Warning: List of file names overflow");
! 605: mch_delay(3000L, TRUE); /* make sure it is noticed */
! 606: top_file_num = 1;
! 607: }
! 608:
! 609: buf->b_winlnum->wl_lnum = lnum;
! 610: buf->b_winlnum->wl_next = NULL;
! 611: buf->b_winlnum->wl_prev = NULL;
! 612: buf->b_winlnum->wl_win = curwin;
! 613: }
! 614:
! 615: if (did_cd)
! 616: buf->b_xfilename = buf->b_filename;
! 617: else
! 618: buf->b_xfilename = buf->b_sfilename;
! 619: buf->b_u_synced = TRUE;
! 620: buf->b_neverloaded = TRUE;
! 621: buf_clear(buf);
! 622: clrallmarks(buf); /* clear marks */
! 623: fmarks_check_names(buf); /* check file marks for this file */
! 624:
! 625: return buf;
! 626: }
! 627:
! 628: /*
! 629: * Free the memory for a BUF structure and its options
! 630: */
! 631: static void
! 632: free_buf_options(buf)
! 633: BUF *buf;
! 634: {
! 635: free_string_option(buf->b_p_fo);
! 636: free_string_option(buf->b_p_isk);
! 637: free_string_option(buf->b_p_com);
! 638: #ifdef CINDENT
! 639: free_string_option(buf->b_p_cink);
! 640: free_string_option(buf->b_p_cino);
! 641: #endif
! 642: #if defined(CINDENT) || defined(SMARTINDENT)
! 643: free_string_option(buf->b_p_cinw);
! 644: #endif
! 645: vim_free(buf);
! 646: }
! 647:
! 648: /*
! 649: * get alternate file n
! 650: * set linenr to lnum or altlnum if lnum == 0
! 651: * if (options & GETF_SETMARK) call setpcmark()
! 652: * if (options & GETF_ALT) we are jumping to an alternate file.
! 653: *
! 654: * return FAIL for failure, OK for success
! 655: */
! 656: int
! 657: buflist_getfile(n, lnum, options)
! 658: int n;
! 659: linenr_t lnum;
! 660: int options;
! 661: {
! 662: BUF *buf;
! 663:
! 664: buf = buflist_findnr(n);
! 665: if (buf == NULL)
! 666: {
! 667: if ((options & GETF_ALT) && n == 0)
! 668: emsg(e_noalt);
! 669: else
! 670: EMSGN("buffer %ld not found", n);
! 671: return FAIL;
! 672: }
! 673:
! 674: /* if alternate file is the current buffer, nothing to do */
! 675: if (buf == curbuf)
! 676: return OK;
! 677:
! 678: /* altlnum may be changed by getfile(), get it now */
! 679: if (lnum == 0)
! 680: lnum = buflist_findlnum(buf);
! 681: ++RedrawingDisabled;
! 682: if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK), lnum) <= 0)
! 683: {
! 684: --RedrawingDisabled;
! 685: return OK;
! 686: }
! 687: --RedrawingDisabled;
! 688: return FAIL;
! 689: }
! 690:
! 691: /*
! 692: * go to the last know line number for the current buffer
! 693: */
! 694: void
! 695: buflist_getlnum()
! 696: {
! 697: linenr_t lnum;
! 698:
! 699: curwin->w_cursor.lnum = 1;
! 700: curwin->w_cursor.col = 0;
! 701: lnum = buflist_findlnum(curbuf);
! 702: if (lnum != 0 && lnum <= curbuf->b_ml.ml_line_count)
! 703: curwin->w_cursor.lnum = lnum;
! 704: }
! 705:
! 706: /*
! 707: * find file in buffer list by name (it has to be for the current window)
! 708: * 'fname' must have a full path.
! 709: */
! 710: BUF *
! 711: buflist_findname(fname)
! 712: char_u *fname;
! 713: {
! 714: BUF *buf;
! 715:
! 716: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 717: if (buf->b_filename != NULL && fnamecmp(fname, buf->b_filename) == 0)
! 718: return (buf);
! 719: return NULL;
! 720: }
! 721:
! 722: /*
! 723: * Find file in buffer list by a regexppattern.
! 724: * Return fnum of the found buffer, < 0 for error.
! 725: */
! 726: int
! 727: buflist_findpat(pattern, pattern_end)
! 728: char_u *pattern;
! 729: char_u *pattern_end; /* pointer to first char after pattern */
! 730: {
! 731: BUF *buf;
! 732: regexp *prog;
! 733: int fnum = -1;
! 734: char_u *pat;
! 735: char_u *match;
! 736: int attempt;
! 737: char_u *p;
! 738:
! 739: if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
! 740: {
! 741: if (*pattern == '%')
! 742: fnum = curbuf->b_fnum;
! 743: else
! 744: fnum = curwin->w_alt_fnum;
! 745: }
! 746:
! 747: /*
! 748: * Try four ways of matching:
! 749: * attempt == 0: without '^' or '$' (at any position)
! 750: * attempt == 1: with '^' at start (only at postion 0)
! 751: * attempt == 2: with '$' at end (only match at end)
! 752: * attempt == 3: with '^' at start and '$' at end (only full match)
! 753: */
! 754: else for (attempt = 0; attempt <= 3; ++attempt)
! 755: {
! 756: /* may add '^' and '$' */
! 757: pat = file_pat_to_reg_pat(pattern, pattern_end, NULL);
! 758: if (pat == NULL)
! 759: return -1;
! 760: if (attempt < 2)
! 761: {
! 762: p = pat + STRLEN(pat) - 1;
! 763: if (p > pat && *p == '$') /* remove '$' */
! 764: *p = NUL;
! 765: }
! 766: p = pat;
! 767: if (*p == '^' && !(attempt & 1)) /* remove '^' */
! 768: ++p;
! 769: prog = vim_regcomp(p);
! 770: vim_free(pat);
! 771: if (prog == NULL)
! 772: return -1;
! 773:
! 774: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 775: {
! 776: match = buflist_match(prog, buf);
! 777: if (match != NULL)
! 778: {
! 779: if (fnum >= 0) /* already found a match */
! 780: {
! 781: fnum = -2;
! 782: break;
! 783: }
! 784: fnum = buf->b_fnum; /* remember first match */
! 785: }
! 786: }
! 787: vim_free(prog);
! 788: if (fnum >= 0) /* found one match */
! 789: break;
! 790: }
! 791:
! 792: if (fnum == -2)
! 793: EMSG2("More than one match for %s", pattern);
! 794: if (fnum < 1)
! 795: EMSG2("No matching buffer for %s", pattern);
! 796: return fnum;
! 797: }
! 798:
! 799: /*
! 800: * Find all buffer names that match.
! 801: * For command line expansion of ":buf" and ":sbuf".
! 802: * Return OK if matches found, FAIL otherwise.
! 803: */
! 804: int
! 805: ExpandBufnames(pat, num_file, file, options)
! 806: char_u *pat;
! 807: int *num_file;
! 808: char_u ***file;
! 809: int options;
! 810: {
! 811: int count = 0;
! 812: BUF *buf;
! 813: int round;
! 814: char_u *p;
! 815: int attempt;
! 816: regexp *prog;
! 817:
! 818: *num_file = 0; /* return values in case of FAIL */
! 819: *file = NULL;
! 820:
! 821: /*
! 822: * attempt == 1: try match with '^', match at start
! 823: * attempt == 2: try match without '^', match anywhere
! 824: */
! 825: for (attempt = 1; attempt <= 2; ++attempt)
! 826: {
! 827: if (attempt == 2)
! 828: {
! 829: if (*pat != '^') /* there's no '^', no need to try again */
! 830: break;
! 831: ++pat; /* skip the '^' */
! 832: }
! 833: prog = vim_regcomp(pat);
! 834: if (prog == NULL)
! 835: return FAIL;
! 836:
! 837: /*
! 838: * round == 1: Count the matches.
! 839: * round == 2: Build the array to keep the matches.
! 840: */
! 841: for (round = 1; round <= 2; ++round)
! 842: {
! 843: count = 0;
! 844: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 845: {
! 846: p = buflist_match(prog, buf);
! 847: if (p != NULL)
! 848: {
! 849: if (round == 1)
! 850: ++count;
! 851: else
! 852: {
! 853: if (options & WILD_HOME_REPLACE)
! 854: p = home_replace_save(buf, p);
! 855: else
! 856: p = strsave(p);
! 857: (*file)[count++] = p;
! 858: }
! 859: }
! 860: }
! 861: if (count == 0) /* no match found, break here */
! 862: break;
! 863: if (round == 1)
! 864: {
! 865: *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
! 866: if (*file == NULL)
! 867: {
! 868: vim_free(prog);
! 869: return FAIL;
! 870: }
! 871: }
! 872: }
! 873: vim_free(prog);
! 874: if (count) /* match(es) found, break here */
! 875: break;
! 876: }
! 877:
! 878: *num_file = count;
! 879: return (count == 0 ? FAIL : OK);
! 880: }
! 881:
! 882: /*
! 883: * Check for a match on the file name for buffer "buf" with regex prog "prog".
! 884: */
! 885: static char_u *
! 886: buflist_match(prog, buf)
! 887: regexp *prog;
! 888: BUF *buf;
! 889: {
! 890: char_u *match = NULL;
! 891:
! 892: if (buf->b_sfilename != NULL &&
! 893: vim_regexec(prog, buf->b_sfilename, TRUE) != 0)
! 894: match = buf->b_sfilename;
! 895: else if (buf->b_filename != NULL)
! 896: {
! 897: if (vim_regexec(prog, buf->b_filename, TRUE) != 0)
! 898: match = buf->b_filename;
! 899: else
! 900: {
! 901: home_replace(NULL, buf->b_filename, NameBuff, MAXPATHL);
! 902: if (vim_regexec(prog, NameBuff, TRUE) != 0)
! 903: match = buf->b_filename;
! 904: }
! 905: }
! 906: return match;
! 907: }
! 908:
! 909: /*
! 910: * find file in buffer name list by number
! 911: */
! 912: BUF *
! 913: buflist_findnr(nr)
! 914: int nr;
! 915: {
! 916: BUF *buf;
! 917:
! 918: if (nr == 0)
! 919: nr = curwin->w_alt_fnum;
! 920: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 921: if (buf->b_fnum == nr)
! 922: return (buf);
! 923: return NULL;
! 924: }
! 925:
! 926: /*
! 927: * get name of file 'n' in the buffer list
! 928: */
! 929: char_u *
! 930: buflist_nr2name(n, fullname, helptail)
! 931: int n;
! 932: int fullname;
! 933: int helptail; /* for help buffers return tail only */
! 934: {
! 935: BUF *buf;
! 936: char_u *fname;
! 937:
! 938: buf = buflist_findnr(n);
! 939: if (buf == NULL)
! 940: return NULL;
! 941: if (fullname)
! 942: fname = buf->b_filename;
! 943: else
! 944: fname = buf->b_xfilename;
! 945: home_replace(helptail ? buf : NULL, fname, NameBuff, MAXPATHL);
! 946: return NameBuff;
! 947: }
! 948:
! 949: /*
! 950: * set the lnum for the buffer 'buf' and the current window
! 951: */
! 952: static void
! 953: buflist_setlnum(buf, lnum)
! 954: BUF *buf;
! 955: linenr_t lnum;
! 956: {
! 957: WINLNUM *wlp;
! 958:
! 959: for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
! 960: if (wlp->wl_win == curwin)
! 961: break;
! 962: if (wlp == NULL) /* make new entry */
! 963: {
! 964: wlp = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
! 965: if (wlp == NULL)
! 966: return;
! 967: wlp->wl_win = curwin;
! 968: }
! 969: else /* remove entry from list */
! 970: {
! 971: if (wlp->wl_prev)
! 972: wlp->wl_prev->wl_next = wlp->wl_next;
! 973: else
! 974: buf->b_winlnum = wlp->wl_next;
! 975: if (wlp->wl_next)
! 976: wlp->wl_next->wl_prev = wlp->wl_prev;
! 977: }
! 978: wlp->wl_lnum = lnum;
! 979: /*
! 980: * insert entry in front of the list
! 981: */
! 982: wlp->wl_next = buf->b_winlnum;
! 983: buf->b_winlnum = wlp;
! 984: wlp->wl_prev = NULL;
! 985: if (wlp->wl_next)
! 986: wlp->wl_next->wl_prev = wlp;
! 987:
! 988: return;
! 989: }
! 990:
! 991: /*
! 992: * find the lnum for the buffer 'buf' for the current window
! 993: */
! 994: static linenr_t
! 995: buflist_findlnum(buf)
! 996: BUF *buf;
! 997: {
! 998: WINLNUM *wlp;
! 999:
! 1000: for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
! 1001: if (wlp->wl_win == curwin)
! 1002: break;
! 1003:
! 1004: if (wlp == NULL) /* if no lnum for curwin, use the first in the list */
! 1005: wlp = buf->b_winlnum;
! 1006:
! 1007: if (wlp)
! 1008: return wlp->wl_lnum;
! 1009: else
! 1010: return (linenr_t)1;
! 1011: }
! 1012:
! 1013: /*
! 1014: * list all know file names (for :files and :buffers command)
! 1015: */
! 1016: void
! 1017: buflist_list()
! 1018: {
! 1019: BUF *buf;
! 1020: int len;
! 1021:
! 1022: for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
! 1023: {
! 1024: msg_outchar('\n');
! 1025: if (buf->b_xfilename == NULL)
! 1026: STRCPY(NameBuff, "No File");
! 1027: else
! 1028: /* careful: home_replace calls vim_getenv(), which uses IObuff! */
! 1029: home_replace(buf, buf->b_xfilename, NameBuff, MAXPATHL);
! 1030:
! 1031: sprintf((char *)IObuff, "%3d %c%c%c \"",
! 1032: buf->b_fnum,
! 1033: buf == curbuf ? '%' :
! 1034: (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
! 1035: buf->b_ml.ml_mfp == NULL ? '-' :
! 1036: (buf->b_nwindows == 0 ? 'h' : ' '),
! 1037: buf->b_changed ? '+' : ' ');
! 1038:
! 1039: len = STRLEN(IObuff);
! 1040: STRNCPY(IObuff + len, NameBuff, IOSIZE - 20 - len);
! 1041:
! 1042: len = STRLEN(IObuff);
! 1043: IObuff[len++] = '"';
! 1044: /*
! 1045: * try to put the "line" strings in column 40
! 1046: */
! 1047: do
! 1048: {
! 1049: IObuff[len++] = ' ';
! 1050: } while (len < 40 && len < IOSIZE - 18);
! 1051: sprintf((char *)IObuff + len, "line %ld",
! 1052: buf == curbuf ? curwin->w_cursor.lnum :
! 1053: (long)buflist_findlnum(buf));
! 1054: msg_outtrans(IObuff);
! 1055: flushbuf(); /* output one line at a time */
! 1056: mch_breakcheck();
! 1057: }
! 1058: }
! 1059:
! 1060: /*
! 1061: * get file name and line number for file 'fnum'
! 1062: * used by DoOneCmd() for translating '%' and '#'
! 1063: * return FAIL if not found, OK for success
! 1064: */
! 1065: int
! 1066: buflist_name_nr(fnum, fname, lnum)
! 1067: int fnum;
! 1068: char_u **fname;
! 1069: linenr_t *lnum;
! 1070: {
! 1071: BUF *buf;
! 1072:
! 1073: buf = buflist_findnr(fnum);
! 1074: if (buf == NULL || buf->b_filename == NULL)
! 1075: return FAIL;
! 1076:
! 1077: if (did_cd)
! 1078: *fname = buf->b_filename;
! 1079: else
! 1080: *fname = buf->b_sfilename;
! 1081: *lnum = buflist_findlnum(buf);
! 1082:
! 1083: return OK;
! 1084: }
! 1085:
! 1086: /*
! 1087: * Set the current file name to 's', short file name to 'ss'.
! 1088: * The file name with the full path is also remembered, for when :cd is used.
! 1089: * Returns FAIL for failure (file name already in use by other buffer)
! 1090: * OK otherwise.
! 1091: */
! 1092: int
! 1093: setfname(fname, sfname, message)
! 1094: char_u *fname, *sfname;
! 1095: int message;
! 1096: {
! 1097: BUF *buf;
! 1098:
! 1099: if (fname == NULL || *fname == NUL)
! 1100: {
! 1101: vim_free(curbuf->b_filename);
! 1102: vim_free(curbuf->b_sfilename);
! 1103: curbuf->b_filename = NULL;
! 1104: curbuf->b_sfilename = NULL;
! 1105: }
! 1106: else
! 1107: {
! 1108: fname_expand(&fname, &sfname);
! 1109: #ifdef USE_FNAME_CASE
! 1110: # ifdef USE_LONG_FNAME
! 1111: if (USE_LONG_FNAME)
! 1112: # endif
! 1113: fname_case(sfname); /* set correct case for short filename */
! 1114: #endif
! 1115: /*
! 1116: * if the file name is already used in another buffer:
! 1117: * - if the buffer is loaded, fail
! 1118: * - if the buffer is not loaded, delete it from the list
! 1119: */
! 1120: buf = buflist_findname(fname);
! 1121: if (buf != NULL && buf != curbuf)
! 1122: {
! 1123: if (buf->b_ml.ml_mfp != NULL) /* it's loaded, fail */
! 1124: {
! 1125: if (message)
! 1126: EMSG("Buffer with this name already exists");
! 1127: return FAIL;
! 1128: }
! 1129: close_buffer(NULL, buf, TRUE, TRUE); /* delete from the list */
! 1130: }
! 1131: fname = strsave(fname);
! 1132: sfname = strsave(sfname);
! 1133: if (fname == NULL || sfname == NULL)
! 1134: {
! 1135: vim_free(sfname);
! 1136: vim_free(fname);
! 1137: return FAIL;
! 1138: }
! 1139: vim_free(curbuf->b_filename);
! 1140: vim_free(curbuf->b_sfilename);
! 1141: curbuf->b_filename = fname;
! 1142: curbuf->b_sfilename = sfname;
! 1143: }
! 1144: if (did_cd)
! 1145: curbuf->b_xfilename = curbuf->b_filename;
! 1146: else
! 1147: curbuf->b_xfilename = curbuf->b_sfilename;
! 1148:
! 1149: #ifndef SHORT_FNAME
! 1150: curbuf->b_shortname = FALSE;
! 1151: #endif
! 1152: /*
! 1153: * If the file name changed, also change the name of the swapfile
! 1154: */
! 1155: if (curbuf->b_ml.ml_mfp != NULL)
! 1156: ml_setname();
! 1157:
! 1158: check_arg_idx(); /* check file name for arg list */
! 1159: maketitle(); /* set window title */
! 1160: status_redraw_all(); /* status lines need to be redrawn */
! 1161: fmarks_check_names(curbuf); /* check named file marks */
! 1162: ml_timestamp(curbuf); /* reset timestamp */
! 1163: return OK;
! 1164: }
! 1165:
! 1166: /*
! 1167: * set alternate file name for current window
! 1168: *
! 1169: * used by dowrite() and do_ecmd()
! 1170: */
! 1171: void
! 1172: setaltfname(fname, sfname, lnum)
! 1173: char_u *fname;
! 1174: char_u *sfname;
! 1175: linenr_t lnum;
! 1176: {
! 1177: BUF *buf;
! 1178:
! 1179: buf = buflist_new(fname, sfname, lnum, FALSE);
! 1180: if (buf != NULL)
! 1181: curwin->w_alt_fnum = buf->b_fnum;
! 1182: }
! 1183:
! 1184: /*
! 1185: * add a file name to the buflist and return its number
! 1186: *
! 1187: * used by qf_init(), main() and doarglist()
! 1188: */
! 1189: int
! 1190: buflist_add(fname)
! 1191: char_u *fname;
! 1192: {
! 1193: BUF *buf;
! 1194:
! 1195: buf = buflist_new(fname, NULL, (linenr_t)0, FALSE);
! 1196: if (buf != NULL)
! 1197: return buf->b_fnum;
! 1198: return 0;
! 1199: }
! 1200:
! 1201: /*
! 1202: * set alternate lnum for current window
! 1203: */
! 1204: void
! 1205: buflist_altlnum()
! 1206: {
! 1207: buflist_setlnum(curbuf, curwin->w_cursor.lnum);
! 1208: }
! 1209:
! 1210: /*
! 1211: * return nonzero if 'fname' is not the same file as current file
! 1212: * fname must have a full path (expanded by FullName)
! 1213: */
! 1214: int
! 1215: otherfile(fname)
! 1216: char_u *fname;
! 1217: { /* no name is different */
! 1218: if (fname == NULL || *fname == NUL || curbuf->b_filename == NULL)
! 1219: return TRUE;
! 1220: return fnamecmp(fname, curbuf->b_filename);
! 1221: }
! 1222:
! 1223: void
! 1224: fileinfo(fullname, shorthelp, dont_truncate)
! 1225: int fullname;
! 1226: int shorthelp;
! 1227: int dont_truncate;
! 1228: {
! 1229: char_u *name;
! 1230: int n;
! 1231: char_u *p;
! 1232: char_u *buffer;
! 1233:
! 1234: buffer = alloc(IOSIZE);
! 1235: if (buffer == NULL)
! 1236: return;
! 1237:
! 1238: if (fullname > 1) /* 2 CTRL-G: include buffer number */
! 1239: {
! 1240: sprintf((char *)buffer, "buf %d: ", curbuf->b_fnum);
! 1241: p = buffer + STRLEN(buffer);
! 1242: }
! 1243: else
! 1244: p = buffer;
! 1245:
! 1246: *p++ = '"';
! 1247: if (curbuf->b_filename == NULL)
! 1248: STRCPY(p, "No File");
! 1249: else
! 1250: {
! 1251: if (!fullname && curbuf->b_sfilename != NULL)
! 1252: name = curbuf->b_sfilename;
! 1253: else
! 1254: name = curbuf->b_filename;
! 1255: home_replace(shorthelp ? curbuf : NULL, name, p,
! 1256: (int)(IOSIZE - (p - buffer)));
! 1257: }
! 1258:
! 1259: sprintf((char *)buffer + STRLEN(buffer),
! 1260: "\"%s%s%s%s",
! 1261: curbuf->b_changed ? (shortmess(SHM_MOD) ?
! 1262: " [+]" : " [Modified]") : " ",
! 1263: curbuf->b_notedited ? "[Not edited]" : "",
! 1264: curbuf->b_p_ro ? (shortmess(SHM_RO) ? "[RO]" : "[readonly]") : "",
! 1265: (curbuf->b_changed || curbuf->b_notedited || curbuf->b_p_ro) ?
! 1266: " " : "");
! 1267: n = (int)(((long)curwin->w_cursor.lnum * 100L) /
! 1268: (long)curbuf->b_ml.ml_line_count);
! 1269: if (curbuf->b_ml.ml_flags & ML_EMPTY)
! 1270: {
! 1271: STRCPY(buffer + STRLEN(buffer), no_lines_msg);
! 1272: }
! 1273: else if (p_ru)
! 1274: {
! 1275: /* Current line and column are already on the screen -- webb */
! 1276: sprintf((char *)buffer + STRLEN(buffer),
! 1277: "%ld line%s --%d%%--",
! 1278: (long)curbuf->b_ml.ml_line_count,
! 1279: plural((long)curbuf->b_ml.ml_line_count),
! 1280: n);
! 1281: }
! 1282: else
! 1283: {
! 1284: sprintf((char *)buffer + STRLEN(buffer),
! 1285: "line %ld of %ld --%d%%-- col ",
! 1286: (long)curwin->w_cursor.lnum,
! 1287: (long)curbuf->b_ml.ml_line_count,
! 1288: n);
! 1289: col_print(buffer + STRLEN(buffer),
! 1290: (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
! 1291: }
! 1292:
! 1293: append_arg_number(buffer, !shortmess(SHM_FILE));
! 1294:
! 1295: if (dont_truncate)
! 1296: msg(buffer);
! 1297: else
! 1298: msg_trunc(buffer);
! 1299:
! 1300: vim_free(buffer);
! 1301: }
! 1302:
! 1303: /*
! 1304: * Give some info about the position of the cursor (for "g CTRL-G").
! 1305: */
! 1306: void
! 1307: cursor_pos_info()
! 1308: {
! 1309: char_u *p;
! 1310: char_u buf1[20];
! 1311: char_u buf2[20];
! 1312: linenr_t lnum;
! 1313: long char_count = 0;
! 1314: long char_count_cursor = 0;
! 1315: int eol_size;
! 1316:
! 1317: /*
! 1318: * Compute the length of the file in characters.
! 1319: */
! 1320: if (curbuf->b_ml.ml_flags & ML_EMPTY)
! 1321: {
! 1322: MSG(no_lines_msg);
! 1323: }
! 1324: else
! 1325: {
! 1326: if (curbuf->b_p_tx)
! 1327: eol_size = 2;
! 1328: else
! 1329: eol_size = 1;
! 1330: for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
! 1331: {
! 1332: if (lnum == curwin->w_cursor.lnum)
! 1333: char_count_cursor = char_count + curwin->w_cursor.col + 1;
! 1334: char_count += STRLEN(ml_get(lnum)) + eol_size;
! 1335: }
! 1336: if (!curbuf->b_p_eol && curbuf->b_p_bin)
! 1337: char_count -= eol_size;
! 1338:
! 1339: p = ml_get_curline();
! 1340: col_print(buf1, (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
! 1341: col_print(buf2, (int)STRLEN(p), linetabsize(p));
! 1342:
! 1343: sprintf((char *)IObuff, "Col %s of %s; Line %ld of %ld; Char %ld of %ld",
! 1344: (char *)buf1, (char *)buf2,
! 1345: (long)curwin->w_cursor.lnum, (long)curbuf->b_ml.ml_line_count,
! 1346: char_count_cursor, char_count);
! 1347: msg(IObuff);
! 1348: }
! 1349: }
! 1350:
! 1351: void
! 1352: col_print(buf, col, vcol)
! 1353: char_u *buf;
! 1354: int col;
! 1355: int vcol;
! 1356: {
! 1357: if (col == vcol)
! 1358: sprintf((char *)buf, "%d", col);
! 1359: else
! 1360: sprintf((char *)buf, "%d-%d", col, vcol);
! 1361: }
! 1362:
! 1363: /*
! 1364: * put filename in title bar of window and in icon title
! 1365: */
! 1366:
! 1367: static char_u *lasttitle = NULL;
! 1368: static char_u *lasticon = NULL;
! 1369:
! 1370: void
! 1371: maketitle()
! 1372: {
! 1373: char_u *t_name;
! 1374: char_u *i_name;
! 1375:
! 1376: if (curbuf->b_filename == NULL)
! 1377: {
! 1378: t_name = (char_u *)"";
! 1379: i_name = (char_u *)"No File";
! 1380: }
! 1381: else
! 1382: {
! 1383: home_replace(curbuf, curbuf->b_filename, IObuff, IOSIZE);
! 1384: append_arg_number(IObuff, FALSE);
! 1385: t_name = IObuff;
! 1386: i_name = gettail(curbuf->b_filename); /* use filename only for icon */
! 1387: }
! 1388:
! 1389: vim_free(lasttitle);
! 1390: if (p_title && (lasttitle = alloc((unsigned)(strsize(t_name) + 7))) != NULL)
! 1391: {
! 1392: STRCPY(lasttitle, "VIM - ");
! 1393: while (*t_name)
! 1394: STRCAT(lasttitle, transchar(*t_name++));
! 1395: }
! 1396: else
! 1397: lasttitle = NULL;
! 1398:
! 1399: vim_free(lasticon);
! 1400: if (p_icon && (lasticon = alloc((unsigned)(strsize(i_name) + 1))) != NULL)
! 1401: {
! 1402: *lasticon = NUL;
! 1403: while (*i_name)
! 1404: STRCAT(lasticon, transchar(*i_name++));
! 1405: }
! 1406: else
! 1407: lasticon = NULL;
! 1408:
! 1409: resettitle();
! 1410: }
! 1411:
! 1412: /*
! 1413: * Append (file 2 of 8) to 'buf'.
! 1414: */
! 1415: static void
! 1416: append_arg_number(buf, add_file)
! 1417: char_u *buf;
! 1418: int add_file; /* Add "file" before the arg number */
! 1419: {
! 1420: if (arg_count <= 1) /* nothing to do */
! 1421: return;
! 1422:
! 1423: buf += STRLEN(buf); /* go to the end of the buffer */
! 1424: *buf++ = ' ';
! 1425: *buf++ = '(';
! 1426: if (add_file)
! 1427: {
! 1428: STRCPY(buf, "file ");
! 1429: buf += 5;
! 1430: }
! 1431: sprintf((char *)buf, curwin->w_arg_idx_invalid ? "(%d) of %d)" :
! 1432: "%d of %d)", curwin->w_arg_idx + 1, arg_count);
! 1433: }
! 1434:
! 1435: /*
! 1436: * Put current window title back (used after calling a shell)
! 1437: */
! 1438: void
! 1439: resettitle()
! 1440: {
! 1441: mch_settitle(lasttitle, lasticon);
! 1442: }
! 1443:
! 1444: /*
! 1445: * If fname is not a full path, make it a full path
! 1446: */
! 1447: char_u *
! 1448: fix_fname(fname)
! 1449: char_u *fname;
! 1450: {
! 1451: if (fname != NameBuff) /* if not already expanded */
! 1452: {
! 1453: if (!isFullName(fname))
! 1454: {
! 1455: (void)FullName(fname, NameBuff, MAXPATHL, FALSE);
! 1456: fname = NameBuff;
! 1457: }
! 1458: #ifdef USE_FNAME_CASE
! 1459: else
! 1460: # ifdef USE_LONG_FNAME
! 1461: if (USE_LONG_FNAME)
! 1462: # endif
! 1463: {
! 1464: STRNCPY(NameBuff, fname, MAXPATHL); /* make copy, it may change */
! 1465: fname = NameBuff;
! 1466: fname_case(fname); /* set correct case for filename */
! 1467: }
! 1468: #endif
! 1469: }
! 1470: return fname;
! 1471: }
! 1472:
! 1473: /*
! 1474: * make fname a full file name, set sfname to fname if not NULL
! 1475: */
! 1476: void
! 1477: fname_expand(fname, sfname)
! 1478: char_u **fname;
! 1479: char_u **sfname;
! 1480: {
! 1481: if (*fname == NULL) /* if no file name given, nothing to do */
! 1482: return;
! 1483: if (*sfname == NULL) /* if no short file name given, use fname */
! 1484: *sfname = *fname;
! 1485: *fname = fix_fname(*fname); /* expand to full path */
! 1486: }
! 1487:
! 1488: /*
! 1489: * do_arg_all: open up to 'count' windows, one for each argument
! 1490: */
! 1491: void
! 1492: do_arg_all(count)
! 1493: int count;
! 1494: {
! 1495: int i;
! 1496:
! 1497: if (arg_count <= 1)
! 1498: {
! 1499: /* Don't give this obvious error message. We don't want it when the
! 1500: * ":all" command is in the .vimrc. */
! 1501: /* EMSG("Argument list contains less than 2 files"); */
! 1502: return;
! 1503: }
! 1504: /*
! 1505: * 1. close all but first window
! 1506: * 2. make the desired number of windows
! 1507: * 3. start editing in the windows
! 1508: */
! 1509: setpcmark();
! 1510: close_others(FALSE);
! 1511: curwin->w_arg_idx = 0;
! 1512: if (count > arg_count || count <= 0)
! 1513: count = arg_count;
! 1514: count = make_windows(count);
! 1515: for (i = 0; i < count; ++i)
! 1516: {
! 1517: /* edit file i */
! 1518: (void)do_ecmd(0, arg_files[i], NULL, NULL, TRUE, (linenr_t)1, FALSE);
! 1519: curwin->w_arg_idx = i;
! 1520: if (i == arg_count - 1)
! 1521: arg_had_last = TRUE;
! 1522: if (curwin->w_next == NULL) /* just checking */
! 1523: break;
! 1524: win_enter(curwin->w_next, FALSE);
! 1525: }
! 1526: win_enter(firstwin, FALSE); /* back to first window */
! 1527: }
! 1528:
! 1529: /*
! 1530: * do_arg_all: open a window for each buffer
! 1531: *
! 1532: * 'count' is the maximum number of windows to open.
! 1533: * when 'all' is TRUE, also load inactive buffers
! 1534: */
! 1535: void
! 1536: do_buffer_all(count, all)
! 1537: int count;
! 1538: int all;
! 1539: {
! 1540: int buf_count;
! 1541: BUF *buf;
! 1542: int i;
! 1543:
! 1544: /*
! 1545: * count number of desired windows
! 1546: */
! 1547: buf_count = 0;
! 1548: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
! 1549: if (all || buf->b_ml.ml_mfp != NULL)
! 1550: ++buf_count;
! 1551:
! 1552: if (buf_count == 0) /* Cannot happen? */
! 1553: {
! 1554: EMSG("No relevant entries in buffer list");
! 1555: return;
! 1556: }
! 1557:
! 1558: /*
! 1559: * 1. close all but first window
! 1560: * 2. make the desired number of windows
! 1561: * 3. stuff commands to fill the windows
! 1562: */
! 1563: close_others(FALSE);
! 1564: curwin->w_arg_idx = 0;
! 1565: if (buf_count > count)
! 1566: buf_count = count;
! 1567: buf_count = make_windows(buf_count);
! 1568: buf = firstbuf;
! 1569: for (i = 0; i < buf_count; ++i)
! 1570: {
! 1571: for ( ; buf != NULL; buf = buf->b_next)
! 1572: if (all || buf->b_ml.ml_mfp != NULL)
! 1573: break;
! 1574: if (buf == NULL) /* Cannot happen? */
! 1575: break;
! 1576: if (i != 0)
! 1577: stuffReadbuff((char_u *)"\n\027\027:"); /* CTRL-W CTRL-W */
! 1578: stuffReadbuff((char_u *)":buf "); /* edit Nth buffer */
! 1579: stuffnumReadbuff((long)buf->b_fnum);
! 1580: buf = buf->b_next;
! 1581: }
! 1582: stuffReadbuff((char_u *)"\n100\027k"); /* back to first window */
! 1583: }
! 1584:
! 1585: /*
! 1586: * do_modelines() - process mode lines for the current file
! 1587: *
! 1588: * Returns immediately if the "ml" option isn't set.
! 1589: */
! 1590: static int chk_modeline __ARGS((linenr_t));
! 1591:
! 1592: void
! 1593: do_modelines()
! 1594: {
! 1595: linenr_t lnum;
! 1596: int nmlines;
! 1597:
! 1598: if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
! 1599: return;
! 1600:
! 1601: for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
! 1602: ++lnum)
! 1603: if (chk_modeline(lnum) == FAIL)
! 1604: nmlines = 0;
! 1605:
! 1606: for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines &&
! 1607: lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
! 1608: if (chk_modeline(lnum) == FAIL)
! 1609: nmlines = 0;
! 1610: }
! 1611:
! 1612: /*
! 1613: * chk_modeline() - check a single line for a mode string
! 1614: * Return FAIL if an error encountered.
! 1615: */
! 1616: static int
! 1617: chk_modeline(lnum)
! 1618: linenr_t lnum;
! 1619: {
! 1620: register char_u *s;
! 1621: register char_u *e;
! 1622: char_u *linecopy; /* local copy of any modeline found */
! 1623: int prev;
! 1624: int end;
! 1625: int retval = OK;
! 1626: char_u *save_sourcing_name;
! 1627:
! 1628: prev = -1;
! 1629: for (s = ml_get(lnum); *s != NUL; ++s)
! 1630: {
! 1631: if (prev == -1 || vim_isspace(prev))
! 1632: {
! 1633: if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) ||
! 1634: STRNCMP(s, "vi:", (size_t)3) == 0 ||
! 1635: STRNCMP(s, "vim:", (size_t)4) == 0)
! 1636: break;
! 1637: }
! 1638: prev = *s;
! 1639: }
! 1640:
! 1641: if (*s)
! 1642: {
! 1643: do /* skip over "ex:", "vi:" or "vim:" */
! 1644: ++s;
! 1645: while (s[-1] != ':');
! 1646:
! 1647: s = linecopy = strsave(s); /* copy the line, it will change */
! 1648: if (linecopy == NULL)
! 1649: return FAIL;
! 1650:
! 1651: sourcing_lnum = lnum; /* prepare for emsg() */
! 1652: save_sourcing_name = sourcing_name;
! 1653: sourcing_name = (char_u *)"modelines";
! 1654:
! 1655: end = FALSE;
! 1656: while (end == FALSE)
! 1657: {
! 1658: s = skipwhite(s);
! 1659: if (*s == NUL)
! 1660: break;
! 1661:
! 1662: /*
! 1663: * Find end of set command: ':' or end of line.
! 1664: */
! 1665: for (e = s; (*e != ':' || *(e - 1) == '\\') && *e != NUL; ++e)
! 1666: ;
! 1667: if (*e == NUL)
! 1668: end = TRUE;
! 1669:
! 1670: /*
! 1671: * If there is a "set" command, require a terminating ':' and
! 1672: * ignore the stuff after the ':'.
! 1673: * "vi:set opt opt opt: foo" -- foo not interpreted
! 1674: * "vi:opt opt opt: foo" -- foo interpreted
! 1675: */
! 1676: if (STRNCMP(s, "set ", (size_t)4) == 0)
! 1677: {
! 1678: if (*e != ':') /* no terminating ':'? */
! 1679: break;
! 1680: end = TRUE;
! 1681: s += 4;
! 1682: }
! 1683:
! 1684: *e = NUL; /* truncate the set command */
! 1685: if (do_set(s) == FAIL) /* stop if error found */
! 1686: {
! 1687: retval = FAIL;
! 1688: break;
! 1689: }
! 1690: s = e + 1; /* advance to next part */
! 1691: }
! 1692:
! 1693: sourcing_lnum = 0;
! 1694: sourcing_name = save_sourcing_name;
! 1695:
! 1696: vim_free(linecopy);
! 1697: }
! 1698: return retval;
! 1699: }