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