Annotation of src/usr.bin/vim/buffer.c, Revision 1.1.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: }