blob: d6bd0ebeb5baacc8b9f63b9aba9ef45f7913dcdb [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds.c: some functions for command line commands
12 */
13
Bram Moolenaar8c8de832008-06-24 22:58:06 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
17#ifdef FEAT_EX_EXTRA
18static int linelen __ARGS((int *has_tab));
19#endif
20static void do_filter __ARGS((linenr_T line1, linenr_T line2, exarg_T *eap, char_u *cmd, int do_in, int do_out));
21#ifdef FEAT_VIMINFO
22static char_u *viminfo_filename __ARGS((char_u *));
Bram Moolenaard812df62008-11-09 12:46:09 +000023static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int flags));
Bram Moolenaar071d4272004-06-13 20:20:40 +000024static int viminfo_encoding __ARGS((vir_T *virp));
25static int read_viminfo_up_to_marks __ARGS((vir_T *virp, int forceit, int writing));
26#endif
27
Bram Moolenaar071d4272004-06-13 20:20:40 +000028static int check_readonly __ARGS((int *forceit, buf_T *buf));
29#ifdef FEAT_AUTOCMD
30static void delbuf_msg __ARGS((char_u *name));
31#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000032static int
33#ifdef __BORLANDC__
34 _RTLENTRYF
35#endif
36 help_compare __ARGS((const void *s1, const void *s2));
37
38/*
39 * ":ascii" and "ga".
40 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000041 void
42do_ascii(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +000043 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +000044{
45 int c;
Bram Moolenaar1418a0d2009-01-13 15:58:01 +000046 int cval;
Bram Moolenaar071d4272004-06-13 20:20:40 +000047 char buf1[20];
48 char buf2[20];
49 char_u buf3[7];
50#ifdef FEAT_MBYTE
Bram Moolenaar362e1a32006-03-06 23:29:24 +000051 int cc[MAX_MCO];
52 int ci = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000053 int len;
54
55 if (enc_utf8)
Bram Moolenaar362e1a32006-03-06 23:29:24 +000056 c = utfc_ptr2char(ml_get_cursor(), cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +000057 else
58#endif
59 c = gchar_cursor();
60 if (c == NUL)
61 {
62 MSG("NUL");
63 return;
64 }
65
66#ifdef FEAT_MBYTE
67 IObuff[0] = NUL;
68 if (!has_mbyte || (enc_dbcs != 0 && c < 0x100) || c < 0x80)
69#endif
70 {
71 if (c == NL) /* NUL is stored as NL */
72 c = NUL;
Bram Moolenaar1418a0d2009-01-13 15:58:01 +000073 if (c == CAR && get_fileformat(curbuf) == EOL_MAC)
74 cval = NL; /* NL is stored as CR */
75 else
76 cval = c;
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 if (vim_isprintc_strict(c) && (c < ' '
78#ifndef EBCDIC
79 || c > '~'
80#endif
81 ))
82 {
83 transchar_nonprint(buf3, c);
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +000084 vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3);
Bram Moolenaar071d4272004-06-13 20:20:40 +000085 }
86 else
87 buf1[0] = NUL;
88#ifndef EBCDIC
89 if (c >= 0x80)
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +000090 vim_snprintf(buf2, sizeof(buf2), " <M-%s>",
91 (char *)transchar(c & 0x7f));
Bram Moolenaar071d4272004-06-13 20:20:40 +000092 else
93#endif
94 buf2[0] = NUL;
Bram Moolenaar555b2802005-05-19 21:08:39 +000095 vim_snprintf((char *)IObuff, IOSIZE,
96 _("<%s>%s%s %d, Hex %02x, Octal %03o"),
Bram Moolenaar1418a0d2009-01-13 15:58:01 +000097 transchar(c), buf1, buf2, cval, cval, cval);
Bram Moolenaar071d4272004-06-13 20:20:40 +000098#ifdef FEAT_MBYTE
Bram Moolenaar1f788e72006-09-05 16:30:40 +000099 if (enc_utf8)
100 c = cc[ci++];
101 else
102 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000103#endif
104 }
105
106#ifdef FEAT_MBYTE
107 /* Repeat for combining characters. */
108 while (has_mbyte && (c >= 0x100 || (enc_utf8 && c >= 0x80)))
109 {
110 len = (int)STRLEN(IObuff);
111 /* This assumes every multi-byte char is printable... */
112 if (len > 0)
113 IObuff[len++] = ' ';
114 IObuff[len++] = '<';
Bram Moolenaar1f788e72006-09-05 16:30:40 +0000115 if (enc_utf8 && utf_iscomposing(c)
Bram Moolenaar4770d092006-01-12 23:22:24 +0000116# ifdef USE_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117 && !gui.in_use
Bram Moolenaar4770d092006-01-12 23:22:24 +0000118# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119 )
120 IObuff[len++] = ' '; /* draw composing char on top of a space */
Bram Moolenaar555b2802005-05-19 21:08:39 +0000121 len += (*mb_char2bytes)(c, IObuff + len);
122 vim_snprintf((char *)IObuff + len, IOSIZE - len,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000123 c < 0x10000 ? _("> %d, Hex %04x, Octal %o")
124 : _("> %d, Hex %08x, Octal %o"), c, c, c);
Bram Moolenaar362e1a32006-03-06 23:29:24 +0000125 if (ci == MAX_MCO)
126 break;
Bram Moolenaar1f788e72006-09-05 16:30:40 +0000127 if (enc_utf8)
128 c = cc[ci++];
129 else
130 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131 }
132#endif
133
134 msg(IObuff);
135}
136
137#if defined(FEAT_EX_EXTRA) || defined(PROTO)
138/*
139 * ":left", ":center" and ":right": align text.
140 */
141 void
142ex_align(eap)
143 exarg_T *eap;
144{
145 pos_T save_curpos;
146 int len;
147 int indent = 0;
148 int new_indent;
149 int has_tab;
150 int width;
151
152#ifdef FEAT_RIGHTLEFT
153 if (curwin->w_p_rl)
154 {
155 /* switch left and right aligning */
156 if (eap->cmdidx == CMD_right)
157 eap->cmdidx = CMD_left;
158 else if (eap->cmdidx == CMD_left)
159 eap->cmdidx = CMD_right;
160 }
161#endif
162
163 width = atoi((char *)eap->arg);
164 save_curpos = curwin->w_cursor;
165 if (eap->cmdidx == CMD_left) /* width is used for new indent */
166 {
167 if (width >= 0)
168 indent = width;
169 }
170 else
171 {
172 /*
173 * if 'textwidth' set, use it
174 * else if 'wrapmargin' set, use it
175 * if invalid value, use 80
176 */
177 if (width <= 0)
178 width = curbuf->b_p_tw;
179 if (width == 0 && curbuf->b_p_wm > 0)
180 width = W_WIDTH(curwin) - curbuf->b_p_wm;
181 if (width <= 0)
182 width = 80;
183 }
184
185 if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
186 return;
187
188 for (curwin->w_cursor.lnum = eap->line1;
189 curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum)
190 {
191 if (eap->cmdidx == CMD_left) /* left align */
192 new_indent = indent;
193 else
194 {
Bram Moolenaar89d40322006-08-29 15:30:07 +0000195 has_tab = FALSE; /* avoid uninit warnings */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196 len = linelen(eap->cmdidx == CMD_right ? &has_tab
197 : NULL) - get_indent();
198
199 if (len <= 0) /* skip blank lines */
200 continue;
201
202 if (eap->cmdidx == CMD_center)
203 new_indent = (width - len) / 2;
204 else
205 {
206 new_indent = width - len; /* right align */
207
208 /*
209 * Make sure that embedded TABs don't make the text go too far
210 * to the right.
211 */
212 if (has_tab)
213 while (new_indent > 0)
214 {
215 (void)set_indent(new_indent, 0);
216 if (linelen(NULL) <= width)
217 {
218 /*
219 * Now try to move the line as much as possible to
220 * the right. Stop when it moves too far.
221 */
222 do
223 (void)set_indent(++new_indent, 0);
224 while (linelen(NULL) <= width);
225 --new_indent;
226 break;
227 }
228 --new_indent;
229 }
230 }
231 }
232 if (new_indent < 0)
233 new_indent = 0;
234 (void)set_indent(new_indent, 0); /* set indent */
235 }
236 changed_lines(eap->line1, 0, eap->line2 + 1, 0L);
237 curwin->w_cursor = save_curpos;
238 beginline(BL_WHITE | BL_FIX);
239}
240
241/*
242 * Get the length of the current line, excluding trailing white space.
243 */
244 static int
245linelen(has_tab)
246 int *has_tab;
247{
248 char_u *line;
249 char_u *first;
250 char_u *last;
251 int save;
252 int len;
253
254 /* find the first non-blank character */
255 line = ml_get_curline();
256 first = skipwhite(line);
257
258 /* find the character after the last non-blank character */
259 for (last = first + STRLEN(first);
260 last > first && vim_iswhite(last[-1]); --last)
261 ;
262 save = *last;
263 *last = NUL;
264 len = linetabsize(line); /* get line length */
265 if (has_tab != NULL) /* check for embedded TAB */
266 *has_tab = (vim_strrchr(first, TAB) != NULL);
267 *last = save;
268
269 return len;
270}
271
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000272/* Buffer for two lines used during sorting. They are allocated to
273 * contain the longest line being sorted. */
274static char_u *sortbuf1;
275static char_u *sortbuf2;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000276
277static int sort_ic; /* ignore case */
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000278static int sort_nr; /* sort on number */
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000279static int sort_rx; /* sort on regex instead of skipping it */
280
281static int sort_abort; /* flag to indicate if sorting has been interrupted */
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000282
283/* Struct to store info to be sorted. */
284typedef struct
285{
286 linenr_T lnum; /* line number */
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000287 long start_col_nr; /* starting column number or number */
288 long end_col_nr; /* ending column number */
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000289} sorti_T;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000290
291static int
292#ifdef __BORLANDC__
293_RTLENTRYF
294#endif
295sort_compare __ARGS((const void *s1, const void *s2));
296
297 static int
298#ifdef __BORLANDC__
299_RTLENTRYF
300#endif
301sort_compare(s1, s2)
302 const void *s1;
303 const void *s2;
304{
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000305 sorti_T l1 = *(sorti_T *)s1;
306 sorti_T l2 = *(sorti_T *)s2;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000307 int result = 0;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000308
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000309 /* If the user interrupts, there's no way to stop qsort() immediately, but
Bram Moolenaarb21e5842006-04-16 18:30:08 +0000310 * if we return 0 every time, qsort will assume it's done sorting and
311 * exit. */
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000312 if (sort_abort)
313 return 0;
314 fast_breakcheck();
315 if (got_int)
316 sort_abort = TRUE;
317
Bram Moolenaarb21e5842006-04-16 18:30:08 +0000318 /* When sorting numbers "start_col_nr" is the number, not the column
319 * number. */
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000320 if (sort_nr)
Bram Moolenaarf75d4982010-10-15 20:20:05 +0200321 result = l1.start_col_nr == l2.start_col_nr ? 0
322 : l1.start_col_nr > l2.start_col_nr ? 1 : -1;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000323 else
324 {
Bram Moolenaarb21e5842006-04-16 18:30:08 +0000325 /* We need to copy one line into "sortbuf1", because there is no
326 * guarantee that the first pointer becomes invalid when obtaining the
327 * second one. */
328 STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr,
329 l1.end_col_nr - l1.start_col_nr + 1);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000330 sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0;
Bram Moolenaarb21e5842006-04-16 18:30:08 +0000331 STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr,
332 l2.end_col_nr - l2.start_col_nr + 1);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000333 sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000334
Bram Moolenaarb21e5842006-04-16 18:30:08 +0000335 result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
336 : STRCMP(sortbuf1, sortbuf2);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000337 }
Bram Moolenaarb21e5842006-04-16 18:30:08 +0000338
339 /* If two lines have the same value, preserve the original line order. */
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000340 if (result == 0)
Bram Moolenaarb21e5842006-04-16 18:30:08 +0000341 return (int)(l1.lnum - l2.lnum);
342 return result;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000343}
344
345/*
346 * ":sort".
347 */
348 void
349ex_sort(eap)
350 exarg_T *eap;
351{
352 regmatch_T regmatch;
353 int len;
354 linenr_T lnum;
355 long maxlen = 0;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000356 sorti_T *nrs;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +0000357 size_t count = (size_t)(eap->line2 - eap->line1 + 1);
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000358 size_t i;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000359 char_u *p;
360 char_u *s;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000361 char_u *s2;
362 char_u c; /* temporary character storage */
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000363 int unique = FALSE;
364 long deleted;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000365 colnr_T start_col;
366 colnr_T end_col;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000367 int sort_oct; /* sort on octal number */
368 int sort_hex; /* sort on hex number */
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000369
Bram Moolenaar48c99162008-02-18 18:42:52 +0000370 /* Sorting one line is really quick! */
371 if (count <= 1)
372 return;
373
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000374 if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
375 return;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000376 sortbuf1 = NULL;
377 sortbuf2 = NULL;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000378 regmatch.regprog = NULL;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000379 nrs = (sorti_T *)lalloc((long_u)(count * sizeof(sorti_T)), TRUE);
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000380 if (nrs == NULL)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000381 goto sortend;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000382
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000383 sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000384
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000385 for (p = eap->arg; *p != NUL; ++p)
386 {
387 if (vim_iswhite(*p))
388 ;
389 else if (*p == 'i')
390 sort_ic = TRUE;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000391 else if (*p == 'r')
392 sort_rx = TRUE;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000393 else if (*p == 'n')
394 sort_nr = 2;
395 else if (*p == 'o')
396 sort_oct = 2;
397 else if (*p == 'x')
398 sort_hex = 2;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000399 else if (*p == 'u')
400 unique = TRUE;
Bram Moolenaar0e6830e2005-05-27 20:23:44 +0000401 else if (*p == '"') /* comment start */
402 break;
403 else if (check_nextcmd(p) != NULL)
404 {
405 eap->nextcmd = check_nextcmd(p);
406 break;
407 }
408 else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL)
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000409 {
410 s = skip_regexp(p + 1, *p, TRUE, NULL);
411 if (*s != *p)
412 {
413 EMSG(_(e_invalpat));
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000414 goto sortend;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000415 }
416 *s = NUL;
Bram Moolenaar1256e722007-07-10 15:26:20 +0000417 /* Use last search pattern if sort pattern is empty. */
Bram Moolenaar210f3702013-03-07 16:41:30 +0100418 if (s == p + 1)
419 {
420 if (last_search_pat() == NULL)
421 {
422 EMSG(_(e_noprevre));
423 goto sortend;
424 }
Bram Moolenaar1256e722007-07-10 15:26:20 +0000425 regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
Bram Moolenaar210f3702013-03-07 16:41:30 +0100426 }
Bram Moolenaar1256e722007-07-10 15:26:20 +0000427 else
428 regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000429 if (regmatch.regprog == NULL)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000430 goto sortend;
Bram Moolenaar0e6830e2005-05-27 20:23:44 +0000431 p = s; /* continue after the regexp */
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000432 regmatch.rm_ic = p_ic;
433 }
434 else
435 {
436 EMSG2(_(e_invarg2), p);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000437 goto sortend;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000438 }
439 }
440
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000441 /* Can only have one of 'n', 'o' and 'x'. */
442 if (sort_nr + sort_oct + sort_hex > 2)
443 {
444 EMSG(_(e_invarg));
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000445 goto sortend;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000446 }
447
448 /* From here on "sort_nr" is used as a flag for any number sorting. */
449 sort_nr += sort_oct + sort_hex;
450
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000451 /*
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000452 * Make an array with all line numbers. This avoids having to copy all
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000453 * the lines into allocated memory.
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000454 * When sorting on strings "start_col_nr" is the offset in the line, for
455 * numbers sorting it's the number to sort on. This means the pattern
456 * matching and number conversion only has to be done once per line.
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000457 * Also get the longest line length for allocating "sortbuf".
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000458 */
459 for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
460 {
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000461 s = ml_get(lnum);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000462 len = (int)STRLEN(s);
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000463 if (maxlen < len)
464 maxlen = len;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000465
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000466 start_col = 0;
467 end_col = len;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000468 if (regmatch.regprog != NULL && vim_regexec(&regmatch, s, 0))
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000469 {
470 if (sort_rx)
471 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000472 start_col = (colnr_T)(regmatch.startp[0] - s);
473 end_col = (colnr_T)(regmatch.endp[0] - s);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000474 }
475 else
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000476 start_col = (colnr_T)(regmatch.endp[0] - s);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000477 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000478 else
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000479 if (regmatch.regprog != NULL)
480 end_col = 0;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000481
482 if (sort_nr)
483 {
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000484 /* Make sure vim_str2nr doesn't read any digits past the end
485 * of the match, by temporarily terminating the string there */
486 s2 = s + end_col;
487 c = *s2;
Bram Moolenaarf75d4982010-10-15 20:20:05 +0200488 *s2 = NUL;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000489 /* Sorting on number: Store the number itself. */
Bram Moolenaar1387a602008-07-24 19:31:11 +0000490 p = s + start_col;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000491 if (sort_hex)
Bram Moolenaar1387a602008-07-24 19:31:11 +0000492 s = skiptohex(p);
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000493 else
Bram Moolenaar1387a602008-07-24 19:31:11 +0000494 s = skiptodigit(p);
495 if (s > p && s[-1] == '-')
496 --s; /* include preceding negative sign */
Bram Moolenaarf75d4982010-10-15 20:20:05 +0200497 if (*s == NUL)
498 /* empty line should sort before any number */
499 nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
500 else
501 vim_str2nr(s, NULL, NULL, sort_oct, sort_hex,
502 &nrs[lnum - eap->line1].start_col_nr, NULL);
503 *s2 = c;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000504 }
505 else
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000506 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000507 /* Store the column to sort at. */
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000508 nrs[lnum - eap->line1].start_col_nr = start_col;
509 nrs[lnum - eap->line1].end_col_nr = end_col;
510 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000511
512 nrs[lnum - eap->line1].lnum = lnum;
Bram Moolenaarae5bce12005-08-15 21:41:48 +0000513
514 if (regmatch.regprog != NULL)
515 fast_breakcheck();
516 if (got_int)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000517 goto sortend;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000518 }
519
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000520 /* Allocate a buffer that can hold the longest line. */
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000521 sortbuf1 = alloc((unsigned)maxlen + 1);
522 if (sortbuf1 == NULL)
523 goto sortend;
524 sortbuf2 = alloc((unsigned)maxlen + 1);
525 if (sortbuf2 == NULL)
526 goto sortend;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000527
Bram Moolenaarae5bce12005-08-15 21:41:48 +0000528 /* Sort the array of line numbers. Note: can't be interrupted! */
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000529 qsort((void *)nrs, count, sizeof(sorti_T), sort_compare);
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000530
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000531 if (sort_abort)
532 goto sortend;
533
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000534 /* Insert the lines in the sorted order below the last one. */
535 lnum = eap->line2;
536 for (i = 0; i < count; ++i)
537 {
538 s = ml_get(nrs[eap->forceit ? count - i - 1 : i].lnum);
539 if (!unique || i == 0
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000540 || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0)
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000541 {
542 if (ml_append(lnum++, s, (colnr_T)0, FALSE) == FAIL)
543 break;
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000544 if (unique)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000545 STRCPY(sortbuf1, s);
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000546 }
Bram Moolenaarae5bce12005-08-15 21:41:48 +0000547 fast_breakcheck();
548 if (got_int)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000549 goto sortend;
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000550 }
551
552 /* delete the original lines if appending worked */
553 if (i == count)
554 for (i = 0; i < count; ++i)
555 ml_delete(eap->line1, FALSE);
556 else
557 count = 0;
558
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000559 /* Adjust marks for deleted (or added) lines and prepare for displaying. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000560 deleted = (long)(count - (lnum - eap->line2));
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000561 if (deleted > 0)
562 mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted);
563 else if (deleted < 0)
564 mark_adjust(eap->line2, MAXLNUM, -deleted, 0L);
565 changed_lines(eap->line1, 0, eap->line2 + 1, -deleted);
Bram Moolenaar54ee7752005-05-31 22:22:17 +0000566
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000567 curwin->w_cursor.lnum = eap->line1;
568 beginline(BL_WHITE | BL_FIX);
569
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000570sortend:
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000571 vim_free(nrs);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000572 vim_free(sortbuf1);
573 vim_free(sortbuf2);
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000574 vim_free(regmatch.regprog);
Bram Moolenaarae5bce12005-08-15 21:41:48 +0000575 if (got_int)
576 EMSG(_(e_interr));
Bram Moolenaar67fe1a12005-05-22 22:12:58 +0000577}
578
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579/*
580 * ":retab".
581 */
582 void
583ex_retab(eap)
584 exarg_T *eap;
585{
586 linenr_T lnum;
587 int got_tab = FALSE;
588 long num_spaces = 0;
589 long num_tabs;
590 long len;
591 long col;
592 long vcol;
593 long start_col = 0; /* For start of white-space string */
594 long start_vcol = 0; /* For start of white-space string */
595 int temp;
596 long old_len;
597 char_u *ptr;
598 char_u *new_line = (char_u *)1; /* init to non-NULL */
599 int did_undo; /* called u_save for current line */
600 int new_ts;
601 int save_list;
602 linenr_T first_line = 0; /* first changed line */
603 linenr_T last_line = 0; /* last changed line */
604
605 save_list = curwin->w_p_list;
606 curwin->w_p_list = 0; /* don't want list mode here */
607
608 new_ts = getdigits(&(eap->arg));
609 if (new_ts < 0)
610 {
611 EMSG(_(e_positive));
612 return;
613 }
614 if (new_ts == 0)
615 new_ts = curbuf->b_p_ts;
616 for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum)
617 {
618 ptr = ml_get(lnum);
619 col = 0;
620 vcol = 0;
621 did_undo = FALSE;
622 for (;;)
623 {
624 if (vim_iswhite(ptr[col]))
625 {
626 if (!got_tab && num_spaces == 0)
627 {
628 /* First consecutive white-space */
629 start_vcol = vcol;
630 start_col = col;
631 }
632 if (ptr[col] == ' ')
633 num_spaces++;
634 else
635 got_tab = TRUE;
636 }
637 else
638 {
639 if (got_tab || (eap->forceit && num_spaces > 1))
640 {
641 /* Retabulate this string of white-space */
642
643 /* len is virtual length of white string */
644 len = num_spaces = vcol - start_vcol;
645 num_tabs = 0;
646 if (!curbuf->b_p_et)
647 {
648 temp = new_ts - (start_vcol % new_ts);
649 if (num_spaces >= temp)
650 {
651 num_spaces -= temp;
652 num_tabs++;
653 }
654 num_tabs += num_spaces / new_ts;
655 num_spaces -= (num_spaces / new_ts) * new_ts;
656 }
657 if (curbuf->b_p_et || got_tab ||
658 (num_spaces + num_tabs < len))
659 {
660 if (did_undo == FALSE)
661 {
662 did_undo = TRUE;
663 if (u_save((linenr_T)(lnum - 1),
664 (linenr_T)(lnum + 1)) == FAIL)
665 {
666 new_line = NULL; /* flag out-of-memory */
667 break;
668 }
669 }
670
671 /* len is actual number of white characters used */
672 len = num_spaces + num_tabs;
673 old_len = (long)STRLEN(ptr);
674 new_line = lalloc(old_len - col + start_col + len + 1,
675 TRUE);
676 if (new_line == NULL)
677 break;
678 if (start_col > 0)
679 mch_memmove(new_line, ptr, (size_t)start_col);
680 mch_memmove(new_line + start_col + len,
681 ptr + col, (size_t)(old_len - col + 1));
682 ptr = new_line + start_col;
683 for (col = 0; col < len; col++)
684 ptr[col] = (col < num_tabs) ? '\t' : ' ';
685 ml_replace(lnum, new_line, FALSE);
686 if (first_line == 0)
687 first_line = lnum;
688 last_line = lnum;
689 ptr = new_line;
690 col = start_col + len;
691 }
692 }
693 got_tab = FALSE;
694 num_spaces = 0;
695 }
696 if (ptr[col] == NUL)
697 break;
698 vcol += chartabsize(ptr + col, (colnr_T)vcol);
699#ifdef FEAT_MBYTE
700 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000701 col += (*mb_ptr2len)(ptr + col);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000702 else
703#endif
704 ++col;
705 }
706 if (new_line == NULL) /* out of memory */
707 break;
708 line_breakcheck();
709 }
710 if (got_int)
711 EMSG(_(e_interr));
712
713 if (curbuf->b_p_ts != new_ts)
714 redraw_curbuf_later(NOT_VALID);
715 if (first_line != 0)
716 changed_lines(first_line, 0, last_line + 1, 0L);
717
718 curwin->w_p_list = save_list; /* restore 'list' */
719
720 curbuf->b_p_ts = new_ts;
721 coladvance(curwin->w_curswant);
722
723 u_clearline();
724}
725#endif
726
727/*
728 * :move command - move lines line1-line2 to line dest
729 *
730 * return FAIL for failure, OK otherwise
731 */
732 int
733do_move(line1, line2, dest)
734 linenr_T line1;
735 linenr_T line2;
736 linenr_T dest;
737{
738 char_u *str;
739 linenr_T l;
740 linenr_T extra; /* Num lines added before line1 */
741 linenr_T num_lines; /* Num lines moved */
742 linenr_T last_line; /* Last line in file after adding new text */
743
744 if (dest >= line1 && dest < line2)
745 {
746 EMSG(_("E134: Move lines into themselves"));
747 return FAIL;
748 }
749
750 num_lines = line2 - line1 + 1;
751
752 /*
753 * First we copy the old text to its new location -- webb
754 * Also copy the flag that ":global" command uses.
755 */
756 if (u_save(dest, dest + 1) == FAIL)
757 return FAIL;
758 for (extra = 0, l = line1; l <= line2; l++)
759 {
760 str = vim_strsave(ml_get(l + extra));
761 if (str != NULL)
762 {
763 ml_append(dest + l - line1, str, (colnr_T)0, FALSE);
764 vim_free(str);
765 if (dest < line1)
766 extra++;
767 }
768 }
769
770 /*
771 * Now we must be careful adjusting our marks so that we don't overlap our
772 * mark_adjust() calls.
773 *
774 * We adjust the marks within the old text so that they refer to the
775 * last lines of the file (temporarily), because we know no other marks
776 * will be set there since these line numbers did not exist until we added
777 * our new lines.
778 *
779 * Then we adjust the marks on lines between the old and new text positions
780 * (either forwards or backwards).
781 *
782 * And Finally we adjust the marks we put at the end of the file back to
783 * their final destination at the new text position -- webb
784 */
785 last_line = curbuf->b_ml.ml_line_count;
786 mark_adjust(line1, line2, last_line - line2, 0L);
787 if (dest >= line2)
788 {
789 mark_adjust(line2 + 1, dest, -num_lines, 0L);
790 curbuf->b_op_start.lnum = dest - num_lines + 1;
791 curbuf->b_op_end.lnum = dest;
792 }
793 else
794 {
795 mark_adjust(dest + 1, line1 - 1, num_lines, 0L);
796 curbuf->b_op_start.lnum = dest + 1;
797 curbuf->b_op_end.lnum = dest + num_lines;
798 }
799 curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
800 mark_adjust(last_line - num_lines + 1, last_line,
801 -(last_line - dest - extra), 0L);
802
803 /*
804 * Now we delete the original text -- webb
805 */
806 if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
807 return FAIL;
808
809 for (l = line1; l <= line2; l++)
810 ml_delete(line1 + extra, TRUE);
811
812 if (!global_busy && num_lines > p_report)
813 {
814 if (num_lines == 1)
815 MSG(_("1 line moved"));
816 else
817 smsg((char_u *)_("%ld lines moved"), num_lines);
818 }
819
820 /*
821 * Leave the cursor on the last of the moved lines.
822 */
823 if (dest >= line1)
824 curwin->w_cursor.lnum = dest;
825 else
826 curwin->w_cursor.lnum = dest + (line2 - line1) + 1;
827
828 if (line1 < dest)
Bram Moolenaar0612ec82011-11-30 17:01:58 +0100829 {
830 dest += num_lines + 1;
831 last_line = curbuf->b_ml.ml_line_count;
832 if (dest > last_line + 1)
833 dest = last_line + 1;
834 changed_lines(line1, 0, dest, 0L);
835 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836 else
837 changed_lines(dest + 1, 0, line1 + num_lines, 0L);
838
839 return OK;
840}
841
842/*
843 * ":copy"
844 */
845 void
846ex_copy(line1, line2, n)
847 linenr_T line1;
848 linenr_T line2;
849 linenr_T n;
850{
851 linenr_T count;
852 char_u *p;
853
854 count = line2 - line1 + 1;
855 curbuf->b_op_start.lnum = n + 1;
856 curbuf->b_op_end.lnum = n + count;
857 curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
858
859 /*
860 * there are three situations:
861 * 1. destination is above line1
862 * 2. destination is between line1 and line2
863 * 3. destination is below line2
864 *
865 * n = destination (when starting)
866 * curwin->w_cursor.lnum = destination (while copying)
867 * line1 = start of source (while copying)
868 * line2 = end of source (while copying)
869 */
870 if (u_save(n, n + 1) == FAIL)
871 return;
872
873 curwin->w_cursor.lnum = n;
874 while (line1 <= line2)
875 {
876 /* need to use vim_strsave() because the line will be unlocked within
877 * ml_append() */
878 p = vim_strsave(ml_get(line1));
879 if (p != NULL)
880 {
881 ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, FALSE);
882 vim_free(p);
883 }
884 /* situation 2: skip already copied lines */
885 if (line1 == n)
886 line1 = curwin->w_cursor.lnum;
887 ++line1;
888 if (curwin->w_cursor.lnum < line1)
889 ++line1;
890 if (curwin->w_cursor.lnum < line2)
891 ++line2;
892 ++curwin->w_cursor.lnum;
893 }
894
895 appended_lines_mark(n, count);
896
897 msgmore((long)count);
898}
899
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000900static char_u *prevcmd = NULL; /* the previous command */
901
902#if defined(EXITFREE) || defined(PROTO)
903 void
904free_prev_shellcmd()
905{
906 vim_free(prevcmd);
907}
908#endif
909
Bram Moolenaar071d4272004-06-13 20:20:40 +0000910/*
911 * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
912 * Bangs in the argument are replaced with the previously entered command.
913 * Remember the argument.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000914 */
915 void
916do_bang(addr_count, eap, forceit, do_in, do_out)
917 int addr_count;
918 exarg_T *eap;
919 int forceit;
920 int do_in, do_out;
921{
922 char_u *arg = eap->arg; /* command */
923 linenr_T line1 = eap->line1; /* start of range */
924 linenr_T line2 = eap->line2; /* end of range */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000925 char_u *newcmd = NULL; /* the new command */
926 int free_newcmd = FALSE; /* need to free() newcmd */
927 int ins_prevcmd;
928 char_u *t;
929 char_u *p;
930 char_u *trailarg;
931 int len;
932 int scroll_save = msg_scroll;
933
934 /*
935 * Disallow shell commands for "rvim".
936 * Disallow shell commands from .exrc and .vimrc in current directory for
937 * security reasons.
938 */
939 if (check_restricted() || check_secure())
940 return;
941
942 if (addr_count == 0) /* :! */
943 {
944 msg_scroll = FALSE; /* don't scroll here */
945 autowrite_all();
946 msg_scroll = scroll_save;
947 }
948
949 /*
950 * Try to find an embedded bang, like in :!<cmd> ! [args]
951 * (:!! is indicated by the 'forceit' variable)
952 */
953 ins_prevcmd = forceit;
954 trailarg = arg;
955 do
956 {
957 len = (int)STRLEN(trailarg) + 1;
958 if (newcmd != NULL)
959 len += (int)STRLEN(newcmd);
960 if (ins_prevcmd)
961 {
962 if (prevcmd == NULL)
963 {
964 EMSG(_(e_noprev));
965 vim_free(newcmd);
966 return;
967 }
968 len += (int)STRLEN(prevcmd);
969 }
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +0000970 if ((t = alloc((unsigned)len)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 {
972 vim_free(newcmd);
973 return;
974 }
975 *t = NUL;
976 if (newcmd != NULL)
977 STRCAT(t, newcmd);
978 if (ins_prevcmd)
979 STRCAT(t, prevcmd);
980 p = t + STRLEN(t);
981 STRCAT(t, trailarg);
982 vim_free(newcmd);
983 newcmd = t;
984
985 /*
986 * Scan the rest of the argument for '!', which is replaced by the
987 * previous command. "\!" is replaced by "!" (this is vi compatible).
988 */
989 trailarg = NULL;
990 while (*p)
991 {
Bram Moolenaare60acc12011-05-10 16:41:25 +0200992 if (*p == '!')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000993 {
994 if (p > newcmd && p[-1] == '\\')
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000995 STRMOVE(p - 1, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996 else
997 {
998 trailarg = p;
999 *trailarg++ = NUL;
1000 ins_prevcmd = TRUE;
1001 break;
1002 }
1003 }
1004 ++p;
1005 }
1006 } while (trailarg != NULL);
1007
1008 vim_free(prevcmd);
1009 prevcmd = newcmd;
1010
1011 if (bangredo) /* put cmd in redo buffer for ! command */
1012 {
Bram Moolenaarebefac62005-12-28 22:39:57 +00001013 AppendToRedobuffLit(prevcmd, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014 AppendToRedobuff((char_u *)"\n");
1015 bangredo = FALSE;
1016 }
1017 /*
1018 * Add quotes around the command, for shells that need them.
1019 */
1020 if (*p_shq != NUL)
1021 {
1022 newcmd = alloc((unsigned)(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1));
1023 if (newcmd == NULL)
1024 return;
1025 STRCPY(newcmd, p_shq);
1026 STRCAT(newcmd, prevcmd);
1027 STRCAT(newcmd, p_shq);
1028 free_newcmd = TRUE;
1029 }
1030 if (addr_count == 0) /* :! */
1031 {
1032 /* echo the command */
1033 msg_start();
1034 msg_putchar(':');
1035 msg_putchar('!');
1036 msg_outtrans(newcmd);
1037 msg_clr_eos();
1038 windgoto(msg_row, msg_col);
1039
1040 do_shell(newcmd, 0);
1041 }
1042 else /* :range! */
Bram Moolenaarade00832006-03-10 21:46:58 +00001043 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001044 /* Careful: This may recursively call do_bang() again! (because of
1045 * autocommands) */
1046 do_filter(line1, line2, eap, newcmd, do_in, do_out);
Bram Moolenaarade00832006-03-10 21:46:58 +00001047#ifdef FEAT_AUTOCMD
1048 apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, FALSE, curbuf);
1049#endif
1050 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 if (free_newcmd)
1052 vim_free(newcmd);
1053}
1054
1055/*
1056 * do_filter: filter lines through a command given by the user
1057 *
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001058 * We mostly use temp files and the call_shell() routine here. This would
1059 * normally be done using pipes on a UNIX machine, but this is more portable
1060 * to non-unix machines. The call_shell() routine needs to be able
Bram Moolenaar071d4272004-06-13 20:20:40 +00001061 * to deal with redirection somehow, and should handle things like looking
1062 * at the PATH env. variable, and adding reasonable extensions to the
1063 * command name given by the user. All reasonable versions of call_shell()
1064 * do this.
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001065 * Alternatively, if on Unix and redirecting input or output, but not both,
1066 * and the 'shelltemp' option isn't set, use pipes.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067 * We use input redirection if do_in is TRUE.
1068 * We use output redirection if do_out is TRUE.
1069 */
1070 static void
1071do_filter(line1, line2, eap, cmd, do_in, do_out)
1072 linenr_T line1, line2;
1073 exarg_T *eap; /* for forced 'ff' and 'fenc' */
1074 char_u *cmd;
1075 int do_in, do_out;
1076{
1077 char_u *itmp = NULL;
1078 char_u *otmp = NULL;
1079 linenr_T linecount;
1080 linenr_T read_linecount;
1081 pos_T cursor_save;
1082 char_u *cmd_buf;
1083#ifdef FEAT_AUTOCMD
1084 buf_T *old_curbuf = curbuf;
1085#endif
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001086 int shell_flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087
1088 if (*cmd == NUL) /* no filter command */
1089 return;
1090
1091#ifdef WIN3264
1092 /*
1093 * Check if external commands are allowed now.
1094 */
1095 if (can_end_termcap_mode(TRUE) == FALSE)
1096 return;
1097#endif
1098
1099 cursor_save = curwin->w_cursor;
1100 linecount = line2 - line1 + 1;
1101 curwin->w_cursor.lnum = line1;
1102 curwin->w_cursor.col = 0;
1103 changed_line_abv_curs();
1104 invalidate_botline();
1105
1106 /*
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001107 * When using temp files:
1108 * 1. * Form temp file names
1109 * 2. * Write the lines to a temp file
1110 * 3. Run the filter command on the temp file
1111 * 4. * Read the output of the command into the buffer
1112 * 5. * Delete the original lines to be filtered
1113 * 6. * Remove the temp files
1114 *
1115 * When writing the input with a pipe or when catching the output with a
1116 * pipe only need to do 3.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117 */
1118
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001119 if (do_out)
1120 shell_flags |= SHELL_DOOUT;
1121
Bram Moolenaar68a33fc2012-04-25 16:50:48 +02001122#ifdef FEAT_FILTERPIPE
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001123 if (!do_in && do_out && !p_stmp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001125 /* Use a pipe to fetch stdout of the command, do not use a temp file. */
1126 shell_flags |= SHELL_READ;
1127 curwin->w_cursor.lnum = line2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 }
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001129 else if (do_in && !do_out && !p_stmp)
1130 {
1131 /* Use a pipe to write stdin of the command, do not use a temp file. */
1132 shell_flags |= SHELL_WRITE;
1133 curbuf->b_op_start.lnum = line1;
1134 curbuf->b_op_end.lnum = line2;
1135 }
1136 else if (do_in && do_out && !p_stmp)
1137 {
1138 /* Use a pipe to write stdin and fetch stdout of the command, do not
1139 * use a temp file. */
1140 shell_flags |= SHELL_READ|SHELL_WRITE;
1141 curbuf->b_op_start.lnum = line1;
1142 curbuf->b_op_end.lnum = line2;
1143 curwin->w_cursor.lnum = line2;
1144 }
1145 else
1146#endif
1147 if ((do_in && (itmp = vim_tempname('i')) == NULL)
1148 || (do_out && (otmp = vim_tempname('o')) == NULL))
1149 {
1150 EMSG(_(e_notmp));
1151 goto filterend;
1152 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153
1154/*
1155 * The writing and reading of temp files will not be shown.
1156 * Vi also doesn't do this and the messages are not very informative.
1157 */
1158 ++no_wait_return; /* don't call wait_return() while busy */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001159 if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 FALSE, FALSE, FALSE, TRUE) == FAIL)
1161 {
1162 msg_putchar('\n'); /* keep message from buf_write() */
1163 --no_wait_return;
1164#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1165 if (!aborting())
1166#endif
1167 (void)EMSG2(_(e_notcreate), itmp); /* will call wait_return */
1168 goto filterend;
1169 }
1170#ifdef FEAT_AUTOCMD
1171 if (curbuf != old_curbuf)
1172 goto filterend;
1173#endif
1174
1175 if (!do_out)
1176 msg_putchar('\n');
1177
Bram Moolenaara9aafe52008-05-07 11:10:28 +00001178 /* Create the shell command in allocated memory. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001179 cmd_buf = make_filter_cmd(cmd, itmp, otmp);
1180 if (cmd_buf == NULL)
1181 goto filterend;
1182
1183 windgoto((int)Rows - 1, 0);
1184 cursor_on();
1185
1186 /*
1187 * When not redirecting the output the command can write anything to the
1188 * screen. If 'shellredir' is equal to ">", screen may be messed up by
1189 * stderr output of external command. Clear the screen later.
1190 * If do_in is FALSE, this could be something like ":r !cat", which may
1191 * also mess up the screen, clear it later.
1192 */
1193 if (!do_out || STRCMP(p_srr, ">") == 0 || !do_in)
1194 redraw_later_clear();
1195
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001196 if (do_out)
1197 {
1198 if (u_save((linenr_T)(line2), (linenr_T)(line2 + 1)) == FAIL)
Bram Moolenaara9aafe52008-05-07 11:10:28 +00001199 {
1200 vim_free(cmd_buf);
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001201 goto error;
Bram Moolenaara9aafe52008-05-07 11:10:28 +00001202 }
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001203 redraw_curbuf_later(VALID);
1204 }
1205 read_linecount = curbuf->b_ml.ml_line_count;
1206
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207 /*
1208 * When call_shell() fails wait_return() is called to give the user a
1209 * chance to read the error messages. Otherwise errors are ignored, so you
1210 * can see the error messages from the command that appear on stdout; use
1211 * 'u' to fix the text
1212 * Switch to cooked mode when not redirecting stdin, avoids that something
1213 * like ":r !cat" hangs.
1214 * Pass on the SHELL_DOOUT flag when the output is being redirected.
1215 */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001216 if (call_shell(cmd_buf, SHELL_FILTER | SHELL_COOKED | shell_flags))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217 {
1218 redraw_later_clear();
1219 wait_return(FALSE);
1220 }
1221 vim_free(cmd_buf);
1222
1223 did_check_timestamps = FALSE;
1224 need_check_timestamps = TRUE;
1225
1226 /* When interrupting the shell command, it may still have produced some
1227 * useful output. Reset got_int here, so that readfile() won't cancel
1228 * reading. */
1229 ui_breakcheck();
1230 got_int = FALSE;
1231
1232 if (do_out)
1233 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001234 if (otmp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001236 if (readfile(otmp, NULL, line2, (linenr_T)0, (linenr_T)MAXLNUM,
1237 eap, READ_FILTER) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001239#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1240 if (!aborting())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241#endif
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001242 {
1243 msg_putchar('\n');
1244 EMSG2(_(e_notread), otmp);
1245 }
1246 goto error;
1247 }
1248#ifdef FEAT_AUTOCMD
1249 if (curbuf != old_curbuf)
1250 goto filterend;
1251#endif
1252 }
1253
1254 read_linecount = curbuf->b_ml.ml_line_count - read_linecount;
1255
1256 if (shell_flags & SHELL_READ)
1257 {
1258 curbuf->b_op_start.lnum = line2 + 1;
1259 curbuf->b_op_end.lnum = curwin->w_cursor.lnum;
1260 appended_lines_mark(line2, read_linecount);
1261 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262
1263 if (do_in)
1264 {
1265 if (cmdmod.keepmarks || vim_strchr(p_cpo, CPO_REMMARK) == NULL)
1266 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267 if (read_linecount >= linecount)
1268 /* move all marks from old lines to new lines */
1269 mark_adjust(line1, line2, linecount, 0L);
1270 else
1271 {
1272 /* move marks from old lines to new lines, delete marks
1273 * that are in deleted lines */
1274 mark_adjust(line1, line1 + read_linecount - 1,
1275 linecount, 0L);
1276 mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L);
1277 }
1278 }
1279
1280 /*
1281 * Put cursor on first filtered line for ":range!cmd".
1282 * Adjust '[ and '] (set by buf_write()).
1283 */
1284 curwin->w_cursor.lnum = line1;
1285 del_lines(linecount, TRUE);
1286 curbuf->b_op_start.lnum -= linecount; /* adjust '[ */
1287 curbuf->b_op_end.lnum -= linecount; /* adjust '] */
1288 write_lnum_adjust(-linecount); /* adjust last line
1289 for next write */
Bram Moolenaar8c711452005-01-14 21:53:12 +00001290#ifdef FEAT_FOLDING
1291 foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum);
1292#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 }
1294 else
1295 {
1296 /*
1297 * Put cursor on last new line for ":r !cmd".
1298 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299 linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001300 curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301 }
Bram Moolenaar8c711452005-01-14 21:53:12 +00001302
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303 beginline(BL_WHITE | BL_FIX); /* cursor on first non-blank */
1304 --no_wait_return;
1305
1306 if (linecount > p_report)
1307 {
1308 if (do_in)
1309 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00001310 vim_snprintf((char *)msg_buf, sizeof(msg_buf),
1311 _("%ld lines filtered"), (long)linecount);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312 if (msg(msg_buf) && !msg_scroll)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 /* save message to display it after redraw */
Bram Moolenaar238a5642006-02-21 22:12:05 +00001314 set_keep_msg(msg_buf, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 }
1316 else
1317 msgmore((long)linecount);
1318 }
1319 }
1320 else
1321 {
1322error:
1323 /* put cursor back in same position for ":w !cmd" */
1324 curwin->w_cursor = cursor_save;
1325 --no_wait_return;
1326 wait_return(FALSE);
1327 }
1328
1329filterend:
1330
1331#ifdef FEAT_AUTOCMD
1332 if (curbuf != old_curbuf)
1333 {
1334 --no_wait_return;
1335 EMSG(_("E135: *Filter* Autocommands must not change current buffer"));
1336 }
1337#endif
1338 if (itmp != NULL)
1339 mch_remove(itmp);
1340 if (otmp != NULL)
1341 mch_remove(otmp);
1342 vim_free(itmp);
1343 vim_free(otmp);
1344}
1345
1346/*
1347 * Call a shell to execute a command.
1348 * When "cmd" is NULL start an interactive shell.
1349 */
1350 void
1351do_shell(cmd, flags)
1352 char_u *cmd;
1353 int flags; /* may be SHELL_DOOUT when output is redirected */
1354{
1355 buf_T *buf;
1356#ifndef FEAT_GUI_MSWIN
1357 int save_nwr;
1358#endif
1359#ifdef MSWIN
1360 int winstart = FALSE;
1361#endif
1362
1363 /*
1364 * Disallow shell commands for "rvim".
1365 * Disallow shell commands from .exrc and .vimrc in current directory for
1366 * security reasons.
1367 */
1368 if (check_restricted() || check_secure())
1369 {
1370 msg_end();
1371 return;
1372 }
1373
1374#ifdef MSWIN
1375 /*
1376 * Check if external commands are allowed now.
1377 */
1378 if (can_end_termcap_mode(TRUE) == FALSE)
1379 return;
1380
1381 /*
1382 * Check if ":!start" is used.
1383 */
1384 if (cmd != NULL)
1385 winstart = (STRNICMP(cmd, "start ", 6) == 0);
1386#endif
1387
1388 /*
1389 * For autocommands we want to get the output on the current screen, to
1390 * avoid having to type return below.
1391 */
1392 msg_putchar('\r'); /* put cursor at start of line */
1393#ifdef FEAT_AUTOCMD
1394 if (!autocmd_busy)
1395#endif
1396 {
1397#ifdef MSWIN
1398 if (!winstart)
1399#endif
1400 stoptermcap();
1401 }
1402#ifdef MSWIN
1403 if (!winstart)
1404#endif
1405 msg_putchar('\n'); /* may shift screen one line up */
1406
1407 /* warning message before calling the shell */
1408 if (p_warn
1409#ifdef FEAT_AUTOCMD
1410 && !autocmd_busy
1411#endif
1412 && msg_silent == 0)
1413 for (buf = firstbuf; buf; buf = buf->b_next)
1414 if (bufIsChanged(buf))
1415 {
1416#ifdef FEAT_GUI_MSWIN
1417 if (!winstart)
1418 starttermcap(); /* don't want a message box here */
1419#endif
1420 MSG_PUTS(_("[No write since last change]\n"));
1421#ifdef FEAT_GUI_MSWIN
1422 if (!winstart)
1423 stoptermcap();
1424#endif
1425 break;
1426 }
1427
1428 /* This windgoto is required for when the '\n' resulted in a "delete line
1429 * 1" command to the terminal. */
1430 if (!swapping_screen())
1431 windgoto(msg_row, msg_col);
1432 cursor_on();
1433 (void)call_shell(cmd, SHELL_COOKED | flags);
1434 did_check_timestamps = FALSE;
1435 need_check_timestamps = TRUE;
1436
1437 /*
1438 * put the message cursor at the end of the screen, avoids wait_return()
1439 * to overwrite the text that the external command showed
1440 */
1441 if (!swapping_screen())
1442 {
1443 msg_row = Rows - 1;
1444 msg_col = 0;
1445 }
1446
1447#ifdef FEAT_AUTOCMD
1448 if (autocmd_busy)
1449 {
1450 if (msg_silent == 0)
1451 redraw_later_clear();
1452 }
1453 else
1454#endif
1455 {
1456 /*
1457 * For ":sh" there is no need to call wait_return(), just redraw.
1458 * Also for the Win32 GUI (the output is in a console window).
1459 * Otherwise there is probably text on the screen that the user wants
1460 * to read before redrawing, so call wait_return().
1461 */
1462#ifndef FEAT_GUI_MSWIN
1463 if (cmd == NULL
1464# ifdef WIN3264
1465 || (winstart && !need_wait_return)
1466# endif
1467 )
1468 {
1469 if (msg_silent == 0)
1470 redraw_later_clear();
1471 need_wait_return = FALSE;
1472 }
1473 else
1474 {
1475 /*
1476 * If we switch screens when starttermcap() is called, we really
1477 * want to wait for "hit return to continue".
1478 */
1479 save_nwr = no_wait_return;
1480 if (swapping_screen())
1481 no_wait_return = FALSE;
1482# ifdef AMIGA
1483 wait_return(term_console ? -1 : msg_silent == 0); /* see below */
1484# else
1485 wait_return(msg_silent == 0);
1486# endif
1487 no_wait_return = save_nwr;
1488 }
1489#endif /* FEAT_GUI_W32 */
1490
1491#ifdef MSWIN
1492 if (!winstart) /* if winstart==TRUE, never stopped termcap! */
1493#endif
1494 starttermcap(); /* start termcap if not done by wait_return() */
1495
1496 /*
1497 * In an Amiga window redrawing is caused by asking the window size.
1498 * If we got an interrupt this will not work. The chance that the
1499 * window size is wrong is very small, but we need to redraw the
1500 * screen. Don't do this if ':' hit in wait_return(). THIS IS UGLY
1501 * but it saves an extra redraw.
1502 */
1503#ifdef AMIGA
1504 if (skip_redraw) /* ':' hit in wait_return() */
1505 {
1506 if (msg_silent == 0)
1507 redraw_later_clear();
1508 }
1509 else if (term_console)
1510 {
1511 OUT_STR(IF_EB("\033[0 q", ESC_STR "[0 q")); /* get window size */
1512 if (got_int && msg_silent == 0)
1513 redraw_later_clear(); /* if got_int is TRUE, redraw needed */
1514 else
1515 must_redraw = 0; /* no extra redraw needed */
1516 }
1517#endif
1518 }
1519
1520 /* display any error messages now */
1521 display_errors();
Bram Moolenaarade00832006-03-10 21:46:58 +00001522
1523#ifdef FEAT_AUTOCMD
1524 apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, FALSE, curbuf);
1525#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526}
1527
1528/*
1529 * Create a shell command from a command string, input redirection file and
1530 * output redirection file.
1531 * Returns an allocated string with the shell command, or NULL for failure.
1532 */
1533 char_u *
1534make_filter_cmd(cmd, itmp, otmp)
1535 char_u *cmd; /* command */
1536 char_u *itmp; /* NULL or name of input file */
1537 char_u *otmp; /* NULL or name of output file */
1538{
1539 char_u *buf;
1540 long_u len;
1541
1542 len = (long_u)STRLEN(cmd) + 3; /* "()" + NUL */
1543 if (itmp != NULL)
1544 len += (long_u)STRLEN(itmp) + 9; /* " { < " + " } " */
1545 if (otmp != NULL)
1546 len += (long_u)STRLEN(otmp) + (long_u)STRLEN(p_srr) + 2; /* " " */
1547 buf = lalloc(len, TRUE);
1548 if (buf == NULL)
1549 return NULL;
1550
1551#if (defined(UNIX) && !defined(ARCHIE)) || defined(OS2)
1552 /*
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001553 * Put braces around the command (for concatenated commands) when
1554 * redirecting input and/or output.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001555 */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001556 if (itmp != NULL || otmp != NULL)
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001557 vim_snprintf((char *)buf, len, "(%s)", (char *)cmd);
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00001558 else
1559 STRCPY(buf, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560 if (itmp != NULL)
1561 {
1562 STRCAT(buf, " < ");
1563 STRCAT(buf, itmp);
1564 }
1565#else
1566 /*
1567 * for shells that don't understand braces around commands, at least allow
1568 * the use of commands in a pipe.
1569 */
1570 STRCPY(buf, cmd);
1571 if (itmp != NULL)
1572 {
1573 char_u *p;
1574
1575 /*
1576 * If there is a pipe, we have to put the '<' in front of it.
1577 * Don't do this when 'shellquote' is not empty, otherwise the
1578 * redirection would be inside the quotes.
1579 */
1580 if (*p_shq == NUL)
1581 {
1582 p = vim_strchr(buf, '|');
1583 if (p != NULL)
1584 *p = NUL;
1585 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001586 STRCAT(buf, " <"); /* " < " causes problems on Amiga */
1587 STRCAT(buf, itmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588 if (*p_shq == NUL)
1589 {
1590 p = vim_strchr(cmd, '|');
1591 if (p != NULL)
1592 {
1593 STRCAT(buf, " "); /* insert a space before the '|' for DOS */
1594 STRCAT(buf, p);
1595 }
1596 }
1597 }
1598#endif
1599 if (otmp != NULL)
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001600 append_redir(buf, (int)len, p_srr, otmp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601
1602 return buf;
1603}
1604
1605/*
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001606 * Append output redirection for file "fname" to the end of string buffer
1607 * "buf[buflen]"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 * Works with the 'shellredir' and 'shellpipe' options.
1609 * The caller should make sure that there is enough room:
1610 * STRLEN(opt) + STRLEN(fname) + 3
1611 */
1612 void
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001613append_redir(buf, buflen, opt, fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614 char_u *buf;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001615 int buflen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 char_u *opt;
1617 char_u *fname;
1618{
1619 char_u *p;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001620 char_u *end;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001622 end = buf + STRLEN(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001623 /* find "%s", skipping "%%" */
1624 for (p = opt; (p = vim_strchr(p, '%')) != NULL; ++p)
1625 if (p[1] == 's')
1626 break;
1627 if (p != NULL)
1628 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001629 *end = ' '; /* not really needed? Not with sh, ksh or bash */
1630 vim_snprintf((char *)end + 1, (size_t)(buflen - (end + 1 - buf)),
1631 (char *)opt, (char *)fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001632 }
1633 else
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00001634 vim_snprintf((char *)end, (size_t)(buflen - (end - buf)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635#ifdef FEAT_QUICKFIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 " %s %s",
1637#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638 " %s%s", /* " > %s" causes problems on Amiga */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639#endif
1640 (char *)opt, (char *)fname);
1641}
1642
1643#ifdef FEAT_VIMINFO
1644
1645static int no_viminfo __ARGS((void));
1646static int viminfo_errcnt;
1647
1648 static int
1649no_viminfo()
1650{
1651 /* "vim -i NONE" does not read or write a viminfo file */
1652 return (use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0);
1653}
1654
1655/*
1656 * Report an error for reading a viminfo file.
1657 * Count the number of errors. When there are more than 10, return TRUE.
1658 */
1659 int
1660viminfo_error(errnum, message, line)
1661 char *errnum;
1662 char *message;
1663 char_u *line;
1664{
Bram Moolenaar555b2802005-05-19 21:08:39 +00001665 vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "),
1666 errnum, message);
Bram Moolenaar6c964832007-12-09 18:38:35 +00001667 STRNCAT(IObuff, line, IOSIZE - STRLEN(IObuff) - 1);
Bram Moolenaar758711c2005-02-02 23:11:38 +00001668 if (IObuff[STRLEN(IObuff) - 1] == '\n')
1669 IObuff[STRLEN(IObuff) - 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670 emsg(IObuff);
1671 if (++viminfo_errcnt >= 10)
1672 {
1673 EMSG(_("E136: viminfo: Too many errors, skipping rest of file"));
1674 return TRUE;
1675 }
1676 return FALSE;
1677}
1678
1679/*
1680 * read_viminfo() -- Read the viminfo file. Registers etc. which are already
Bram Moolenaard812df62008-11-09 12:46:09 +00001681 * set are not over-written unless "flags" includes VIF_FORCEIT. -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682 */
1683 int
Bram Moolenaard812df62008-11-09 12:46:09 +00001684read_viminfo(file, flags)
1685 char_u *file; /* file name or NULL to use default name */
1686 int flags; /* VIF_WANT_INFO et al. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687{
1688 FILE *fp;
1689 char_u *fname;
1690
1691 if (no_viminfo())
1692 return FAIL;
1693
Bram Moolenaard812df62008-11-09 12:46:09 +00001694 fname = viminfo_filename(file); /* get file name in allocated buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001695 if (fname == NULL)
1696 return FAIL;
1697 fp = mch_fopen((char *)fname, READBIN);
1698
1699 if (p_verbose > 0)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001700 {
1701 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00001702 smsg((char_u *)_("Reading viminfo file \"%s\"%s%s%s"),
1703 fname,
Bram Moolenaard812df62008-11-09 12:46:09 +00001704 (flags & VIF_WANT_INFO) ? _(" info") : "",
1705 (flags & VIF_WANT_MARKS) ? _(" marks") : "",
1706 (flags & VIF_GET_OLDFILES) ? _(" oldfiles") : "",
Bram Moolenaar555b2802005-05-19 21:08:39 +00001707 fp == NULL ? _(" FAILED") : "");
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001708 verbose_leave();
1709 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710
1711 vim_free(fname);
1712 if (fp == NULL)
1713 return FAIL;
1714
1715 viminfo_errcnt = 0;
Bram Moolenaard812df62008-11-09 12:46:09 +00001716 do_viminfo(fp, NULL, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717
1718 fclose(fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719 return OK;
1720}
1721
1722/*
1723 * write_viminfo() -- Write the viminfo file. The old one is read in first so
1724 * that effectively a merge of current info and old info is done. This allows
1725 * multiple vims to run simultaneously, without losing any marks etc. If
1726 * forceit is TRUE, then the old file is not read in, and only internal info is
1727 * written to the file. -- webb
1728 */
1729 void
1730write_viminfo(file, forceit)
1731 char_u *file;
1732 int forceit;
1733{
1734 char_u *fname;
1735 FILE *fp_in = NULL; /* input viminfo file, if any */
1736 FILE *fp_out = NULL; /* output viminfo file */
1737 char_u *tempname = NULL; /* name of temp viminfo file */
1738 struct stat st_new; /* mch_stat() of potential new file */
1739 char_u *wp;
1740#if defined(UNIX) || defined(VMS)
1741 mode_t umask_save;
1742#endif
1743#ifdef UNIX
1744 int shortname = FALSE; /* use 8.3 file name */
1745 struct stat st_old; /* mch_stat() of existing viminfo file */
1746#endif
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001747#ifdef WIN3264
1748 long perm = -1;
1749#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750
1751 if (no_viminfo())
1752 return;
1753
1754 fname = viminfo_filename(file); /* may set to default if NULL */
1755 if (fname == NULL)
1756 return;
1757
1758 fp_in = mch_fopen((char *)fname, READBIN);
1759 if (fp_in == NULL)
1760 {
1761 /* if it does exist, but we can't read it, don't try writing */
1762 if (mch_stat((char *)fname, &st_new) == 0)
1763 goto end;
1764#if defined(UNIX) || defined(VMS)
1765 /*
1766 * For Unix we create the .viminfo non-accessible for others,
1767 * because it may contain text from non-accessible documents.
1768 */
1769 umask_save = umask(077);
1770#endif
1771 fp_out = mch_fopen((char *)fname, WRITEBIN);
1772#if defined(UNIX) || defined(VMS)
1773 (void)umask(umask_save);
1774#endif
1775 }
1776 else
1777 {
1778 /*
1779 * There is an existing viminfo file. Create a temporary file to
1780 * write the new viminfo into, in the same directory as the
1781 * existing viminfo file, which will be renamed later.
1782 */
1783#ifdef UNIX
1784 /*
1785 * For Unix we check the owner of the file. It's not very nice to
1786 * overwrite a user's viminfo file after a "su root", with a
1787 * viminfo file that the user can't read.
1788 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00001789 st_old.st_dev = (dev_t)0;
Bram Moolenaar6f192452007-11-08 19:49:02 +00001790 st_old.st_ino = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 st_old.st_mode = 0600;
Bram Moolenaar311d9822007-02-27 15:48:28 +00001792 if (mch_stat((char *)fname, &st_old) == 0
1793 && getuid() != ROOT_UID
Bram Moolenaar12625ca2005-11-25 19:58:47 +00001794 && !(st_old.st_uid == getuid()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 ? (st_old.st_mode & 0200)
1796 : (st_old.st_gid == getgid()
1797 ? (st_old.st_mode & 0020)
1798 : (st_old.st_mode & 0002))))
1799 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001800 int tt = msg_didany;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801
1802 /* avoid a wait_return for this message, it's annoying */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 EMSG2(_("E137: Viminfo file is not writable: %s"), fname);
1804 msg_didany = tt;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001805 fclose(fp_in);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 goto end;
1807 }
1808#endif
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001809#ifdef WIN3264
1810 /* Get the file attributes of the existing viminfo file. */
1811 perm = mch_getperm(fname);
1812#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813
1814 /*
1815 * Make tempname.
1816 * May try twice: Once normal and once with shortname set, just in
1817 * case somebody puts his viminfo file in an 8.3 filesystem.
1818 */
1819 for (;;)
1820 {
1821 tempname = buf_modname(
1822#ifdef UNIX
1823 shortname,
1824#else
1825# ifdef SHORT_FNAME
1826 TRUE,
1827# else
1828# ifdef FEAT_GUI_W32
1829 gui_is_win32s(),
1830# else
1831 FALSE,
1832# endif
1833# endif
1834#endif
1835 fname,
1836#ifdef VMS
1837 (char_u *)"-tmp",
1838#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 (char_u *)".tmp",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840#endif
1841 FALSE);
1842 if (tempname == NULL) /* out of memory */
1843 break;
1844
1845 /*
1846 * Check if tempfile already exists. Never overwrite an
1847 * existing file!
1848 */
1849 if (mch_stat((char *)tempname, &st_new) == 0)
1850 {
1851#ifdef UNIX
1852 /*
1853 * Check if tempfile is same as original file. May happen
1854 * when modname() gave the same file back. E.g. silly
1855 * link, or file name-length reached. Try again with
1856 * shortname set.
1857 */
Bram Moolenaar12625ca2005-11-25 19:58:47 +00001858 if (!shortname && st_new.st_dev == st_old.st_dev
1859 && st_new.st_ino == st_old.st_ino)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 {
1861 vim_free(tempname);
1862 tempname = NULL;
1863 shortname = TRUE;
1864 continue;
1865 }
1866#endif
1867 /*
1868 * Try another name. Change one character, just before
1869 * the extension. This should also work for an 8.3
1870 * file name, when after adding the extension it still is
1871 * the same file as the original.
1872 */
1873 wp = tempname + STRLEN(tempname) - 5;
1874 if (wp < gettail(tempname)) /* empty file name? */
1875 wp = gettail(tempname);
1876 for (*wp = 'z'; mch_stat((char *)tempname, &st_new) == 0;
1877 --*wp)
1878 {
1879 /*
1880 * They all exist? Must be something wrong! Don't
1881 * write the viminfo file then.
1882 */
1883 if (*wp == 'a')
1884 {
1885 vim_free(tempname);
1886 tempname = NULL;
1887 break;
1888 }
1889 }
1890 }
1891 break;
1892 }
1893
1894 if (tempname != NULL)
1895 {
Bram Moolenaar114216c2006-03-14 23:08:30 +00001896#ifdef VMS
1897 /* fdopen() fails for some reason */
Bram Moolenaarcf034472006-03-15 23:07:59 +00001898 umask_save = umask(077);
1899 fp_out = mch_fopen((char *)tempname, WRITEBIN);
1900 (void)umask(umask_save);
Bram Moolenaar114216c2006-03-14 23:08:30 +00001901#else
Bram Moolenaara5792f52005-11-23 21:25:05 +00001902 int fd;
1903
1904 /* Use mch_open() to be able to use O_NOFOLLOW and set file
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001905 * protection:
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00001906 * Unix: same as original file, but strip s-bit. Reset umask to
1907 * avoid it getting in the way.
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001908 * Others: r&w for user only. */
Bram Moolenaar114216c2006-03-14 23:08:30 +00001909# ifdef UNIX
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00001910 umask_save = umask(0);
Bram Moolenaara5792f52005-11-23 21:25:05 +00001911 fd = mch_open((char *)tempname,
1912 O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW,
Bram Moolenaarbba577a2005-11-28 23:05:55 +00001913 (int)((st_old.st_mode & 0777) | 0600));
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00001914 (void)umask(umask_save);
Bram Moolenaar114216c2006-03-14 23:08:30 +00001915# else
Bram Moolenaarbba577a2005-11-28 23:05:55 +00001916 fd = mch_open((char *)tempname,
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00001917 O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
Bram Moolenaar114216c2006-03-14 23:08:30 +00001918# endif
Bram Moolenaara5792f52005-11-23 21:25:05 +00001919 if (fd < 0)
1920 fp_out = NULL;
1921 else
1922 fp_out = fdopen(fd, WRITEBIN);
Bram Moolenaar114216c2006-03-14 23:08:30 +00001923#endif /* VMS */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924
1925 /*
1926 * If we can't create in the same directory, try creating a
1927 * "normal" temp file.
1928 */
1929 if (fp_out == NULL)
1930 {
1931 vim_free(tempname);
1932 if ((tempname = vim_tempname('o')) != NULL)
1933 fp_out = mch_fopen((char *)tempname, WRITEBIN);
1934 }
Bram Moolenaara5792f52005-11-23 21:25:05 +00001935
1936#if defined(UNIX) && defined(HAVE_FCHOWN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 /*
Bram Moolenaara5792f52005-11-23 21:25:05 +00001938 * Make sure the owner can read/write it. This only works for
1939 * root.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 */
1941 if (fp_out != NULL)
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00001942 ignored = fchown(fileno(fp_out), st_old.st_uid, st_old.st_gid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943#endif
1944 }
1945 }
1946
1947 /*
1948 * Check if the new viminfo file can be written to.
1949 */
1950 if (fp_out == NULL)
1951 {
1952 EMSG2(_("E138: Can't write viminfo file %s!"),
Bram Moolenaar75c50c42005-06-04 22:06:24 +00001953 (fp_in == NULL || tempname == NULL) ? fname : tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001954 if (fp_in != NULL)
1955 fclose(fp_in);
1956 goto end;
1957 }
1958
1959 if (p_verbose > 0)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001960 {
1961 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00001962 smsg((char_u *)_("Writing viminfo file \"%s\""), fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001963 verbose_leave();
1964 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965
1966 viminfo_errcnt = 0;
Bram Moolenaard812df62008-11-09 12:46:09 +00001967 do_viminfo(fp_in, fp_out, forceit ? 0 : (VIF_WANT_INFO | VIF_WANT_MARKS));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968
1969 fclose(fp_out); /* errors are ignored !? */
1970 if (fp_in != NULL)
1971 {
1972 fclose(fp_in);
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001973
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974 /*
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001975 * In case of an error keep the original viminfo file.
1976 * Otherwise rename the newly written file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977 */
1978 if (viminfo_errcnt || vim_rename(tempname, fname) == -1)
1979 mch_remove(tempname);
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001980
1981#ifdef WIN3264
1982 /* If the viminfo file was hidden then also hide the new file. */
1983 if (perm > 0 && (perm & FILE_ATTRIBUTE_HIDDEN))
1984 mch_hide(fname);
1985#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 }
Bram Moolenaarbca84a12005-12-14 22:08:35 +00001987
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988end:
1989 vim_free(fname);
1990 vim_free(tempname);
1991}
1992
1993/*
1994 * Get the viminfo file name to use.
1995 * If "file" is given and not empty, use it (has already been expanded by
1996 * cmdline functions).
1997 * Otherwise use "-i file_name", value from 'viminfo' or the default, and
1998 * expand environment variables.
1999 * Returns an allocated string. NULL when out of memory.
2000 */
2001 static char_u *
2002viminfo_filename(file)
2003 char_u *file;
2004{
2005 if (file == NULL || *file == NUL)
2006 {
2007 if (use_viminfo != NULL)
2008 file = use_viminfo;
2009 else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
2010 {
2011#ifdef VIMINFO_FILE2
2012 /* don't use $HOME when not defined (turned into "c:/"!). */
2013# ifdef VMS
2014 if (mch_getenv((char_u *)"SYS$LOGIN") == NULL)
2015# else
2016 if (mch_getenv((char_u *)"HOME") == NULL)
2017# endif
2018 {
2019 /* don't use $VIM when not available. */
2020 expand_env((char_u *)"$VIM", NameBuff, MAXPATHL);
2021 if (STRCMP("$VIM", NameBuff) != 0) /* $VIM was expanded */
2022 file = (char_u *)VIMINFO_FILE2;
2023 else
2024 file = (char_u *)VIMINFO_FILE;
2025 }
2026 else
2027#endif
2028 file = (char_u *)VIMINFO_FILE;
2029 }
2030 expand_env(file, NameBuff, MAXPATHL);
2031 file = NameBuff;
2032 }
2033 return vim_strsave(file);
2034}
2035
2036/*
2037 * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo().
2038 */
2039 static void
Bram Moolenaard812df62008-11-09 12:46:09 +00002040do_viminfo(fp_in, fp_out, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041 FILE *fp_in;
2042 FILE *fp_out;
Bram Moolenaard812df62008-11-09 12:46:09 +00002043 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002044{
2045 int count = 0;
2046 int eof = FALSE;
2047 vir_T vir;
2048
2049 if ((vir.vir_line = alloc(LSIZE)) == NULL)
2050 return;
2051 vir.vir_fd = fp_in;
2052#ifdef FEAT_MBYTE
2053 vir.vir_conv.vc_type = CONV_NONE;
2054#endif
2055
2056 if (fp_in != NULL)
2057 {
Bram Moolenaard812df62008-11-09 12:46:09 +00002058 if (flags & VIF_WANT_INFO)
2059 eof = read_viminfo_up_to_marks(&vir,
2060 flags & VIF_FORCEIT, fp_out != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002061 else
2062 /* Skip info, find start of marks */
2063 while (!(eof = viminfo_readline(&vir))
2064 && vir.vir_line[0] != '>')
2065 ;
2066 }
2067 if (fp_out != NULL)
2068 {
2069 /* Write the info: */
2070 fprintf(fp_out, _("# This viminfo file was generated by Vim %s.\n"),
2071 VIM_VERSION_MEDIUM);
Bram Moolenaar2f1e0502010-08-13 11:18:02 +02002072 fputs(_("# You may edit it if you're careful!\n\n"), fp_out);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073#ifdef FEAT_MBYTE
Bram Moolenaar2f1e0502010-08-13 11:18:02 +02002074 fputs(_("# Value of 'encoding' when this file was written\n"), fp_out);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 fprintf(fp_out, "*encoding=%s\n\n", p_enc);
2076#endif
2077 write_viminfo_search_pattern(fp_out);
2078 write_viminfo_sub_string(fp_out);
2079#ifdef FEAT_CMDHIST
2080 write_viminfo_history(fp_out);
2081#endif
2082 write_viminfo_registers(fp_out);
2083#ifdef FEAT_EVAL
2084 write_viminfo_varlist(fp_out);
2085#endif
2086 write_viminfo_filemarks(fp_out);
2087 write_viminfo_bufferlist(fp_out);
2088 count = write_viminfo_marks(fp_out);
2089 }
Bram Moolenaard812df62008-11-09 12:46:09 +00002090 if (fp_in != NULL
2091 && (flags & (VIF_WANT_MARKS | VIF_GET_OLDFILES | VIF_FORCEIT)))
2092 copy_viminfo_marks(&vir, fp_out, count, eof, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093
2094 vim_free(vir.vir_line);
2095#ifdef FEAT_MBYTE
2096 if (vir.vir_conv.vc_type != CONV_NONE)
2097 convert_setup(&vir.vir_conv, NULL, NULL);
2098#endif
2099}
2100
2101/*
2102 * read_viminfo_up_to_marks() -- Only called from do_viminfo(). Reads in the
2103 * first part of the viminfo file which contains everything but the marks that
2104 * are local to a file. Returns TRUE when end-of-file is reached. -- webb
2105 */
2106 static int
2107read_viminfo_up_to_marks(virp, forceit, writing)
2108 vir_T *virp;
2109 int forceit;
2110 int writing;
2111{
2112 int eof;
2113 buf_T *buf;
2114
2115#ifdef FEAT_CMDHIST
2116 prepare_viminfo_history(forceit ? 9999 : 0);
2117#endif
2118 eof = viminfo_readline(virp);
2119 while (!eof && virp->vir_line[0] != '>')
2120 {
2121 switch (virp->vir_line[0])
2122 {
2123 /* Characters reserved for future expansion, ignored now */
2124 case '+': /* "+40 /path/dir file", for running vim without args */
2125 case '|': /* to be defined */
2126 case '^': /* to be defined */
2127 case '<': /* long line - ignored */
2128 /* A comment or empty line. */
2129 case NUL:
2130 case '\r':
2131 case '\n':
2132 case '#':
2133 eof = viminfo_readline(virp);
2134 break;
2135 case '*': /* "*encoding=value" */
2136 eof = viminfo_encoding(virp);
2137 break;
2138 case '!': /* global variable */
2139#ifdef FEAT_EVAL
2140 eof = read_viminfo_varlist(virp, writing);
2141#else
2142 eof = viminfo_readline(virp);
2143#endif
2144 break;
2145 case '%': /* entry for buffer list */
2146 eof = read_viminfo_bufferlist(virp, writing);
2147 break;
2148 case '"':
2149 eof = read_viminfo_register(virp, forceit);
2150 break;
2151 case '/': /* Search string */
2152 case '&': /* Substitute search string */
2153 case '~': /* Last search string, followed by '/' or '&' */
2154 eof = read_viminfo_search_pattern(virp, forceit);
2155 break;
2156 case '$':
2157 eof = read_viminfo_sub_string(virp, forceit);
2158 break;
2159 case ':':
2160 case '?':
2161 case '=':
2162 case '@':
2163#ifdef FEAT_CMDHIST
2164 eof = read_viminfo_history(virp);
2165#else
2166 eof = viminfo_readline(virp);
2167#endif
2168 break;
2169 case '-':
2170 case '\'':
2171 eof = read_viminfo_filemark(virp, forceit);
2172 break;
2173 default:
2174 if (viminfo_error("E575: ", _("Illegal starting char"),
2175 virp->vir_line))
2176 eof = TRUE;
2177 else
2178 eof = viminfo_readline(virp);
2179 break;
2180 }
2181 }
2182
2183#ifdef FEAT_CMDHIST
2184 /* Finish reading history items. */
2185 finish_viminfo_history();
2186#endif
2187
2188 /* Change file names to buffer numbers for fmarks. */
2189 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2190 fmarks_check_names(buf);
2191
2192 return eof;
2193}
2194
2195/*
2196 * Compare the 'encoding' value in the viminfo file with the current value of
2197 * 'encoding'. If different and the 'c' flag is in 'viminfo', setup for
2198 * conversion of text with iconv() in viminfo_readstring().
2199 */
2200 static int
2201viminfo_encoding(virp)
2202 vir_T *virp;
2203{
2204#ifdef FEAT_MBYTE
2205 char_u *p;
2206 int i;
2207
2208 if (get_viminfo_parameter('c') != 0)
2209 {
2210 p = vim_strchr(virp->vir_line, '=');
2211 if (p != NULL)
2212 {
2213 /* remove trailing newline */
2214 ++p;
2215 for (i = 0; vim_isprintc(p[i]); ++i)
2216 ;
2217 p[i] = NUL;
2218
2219 convert_setup(&virp->vir_conv, p, p_enc);
2220 }
2221 }
2222#endif
2223 return viminfo_readline(virp);
2224}
2225
2226/*
2227 * Read a line from the viminfo file.
2228 * Returns TRUE for end-of-file;
2229 */
2230 int
2231viminfo_readline(virp)
2232 vir_T *virp;
2233{
2234 return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd);
2235}
2236
2237/*
2238 * check string read from viminfo file
2239 * remove '\n' at the end of the line
2240 * - replace CTRL-V CTRL-V with CTRL-V
2241 * - replace CTRL-V 'n' with '\n'
2242 *
2243 * Check for a long line as written by viminfo_writestring().
2244 *
2245 * Return the string in allocated memory (NULL when out of memory).
2246 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002247 char_u *
2248viminfo_readstring(virp, off, convert)
2249 vir_T *virp;
2250 int off; /* offset for virp->vir_line */
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002251 int convert UNUSED; /* convert the string */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252{
2253 char_u *retval;
2254 char_u *s, *d;
2255 long len;
2256
2257 if (virp->vir_line[off] == Ctrl_V && vim_isdigit(virp->vir_line[off + 1]))
2258 {
2259 len = atol((char *)virp->vir_line + off + 1);
2260 retval = lalloc(len, TRUE);
2261 if (retval == NULL)
2262 {
2263 /* Line too long? File messed up? Skip next line. */
2264 (void)vim_fgets(virp->vir_line, 10, virp->vir_fd);
2265 return NULL;
2266 }
2267 (void)vim_fgets(retval, (int)len, virp->vir_fd);
2268 s = retval + 1; /* Skip the leading '<' */
2269 }
2270 else
2271 {
2272 retval = vim_strsave(virp->vir_line + off);
2273 if (retval == NULL)
2274 return NULL;
2275 s = retval;
2276 }
2277
2278 /* Change CTRL-V CTRL-V to CTRL-V and CTRL-V n to \n in-place. */
2279 d = retval;
2280 while (*s != NUL && *s != '\n')
2281 {
2282 if (s[0] == Ctrl_V && s[1] != NUL)
2283 {
2284 if (s[1] == 'n')
2285 *d++ = '\n';
2286 else
2287 *d++ = Ctrl_V;
2288 s += 2;
2289 }
2290 else
2291 *d++ = *s++;
2292 }
2293 *d = NUL;
2294
2295#ifdef FEAT_MBYTE
2296 if (convert && virp->vir_conv.vc_type != CONV_NONE && *retval != NUL)
2297 {
2298 d = string_convert(&virp->vir_conv, retval, NULL);
2299 if (d != NULL)
2300 {
2301 vim_free(retval);
2302 retval = d;
2303 }
2304 }
2305#endif
2306
2307 return retval;
2308}
2309
2310/*
2311 * write string to viminfo file
2312 * - replace CTRL-V with CTRL-V CTRL-V
2313 * - replace '\n' with CTRL-V 'n'
2314 * - add a '\n' at the end
2315 *
2316 * For a long line:
2317 * - write " CTRL-V <length> \n " in first line
2318 * - write " < <string> \n " in second line
2319 */
2320 void
2321viminfo_writestring(fd, p)
2322 FILE *fd;
2323 char_u *p;
2324{
2325 int c;
2326 char_u *s;
2327 int len = 0;
2328
2329 for (s = p; *s != NUL; ++s)
2330 {
2331 if (*s == Ctrl_V || *s == '\n')
2332 ++len;
2333 ++len;
2334 }
2335
2336 /* If the string will be too long, write its length and put it in the next
2337 * line. Take into account that some room is needed for what comes before
2338 * the string (e.g., variable name). Add something to the length for the
2339 * '<', NL and trailing NUL. */
2340 if (len > LSIZE / 2)
2341 fprintf(fd, IF_EB("\026%d\n<", CTRL_V_STR "%d\n<"), len + 3);
2342
2343 while ((c = *p++) != NUL)
2344 {
2345 if (c == Ctrl_V || c == '\n')
2346 {
2347 putc(Ctrl_V, fd);
2348 if (c == '\n')
2349 c = 'n';
2350 }
2351 putc(c, fd);
2352 }
2353 putc('\n', fd);
2354}
2355#endif /* FEAT_VIMINFO */
2356
2357/*
2358 * Implementation of ":fixdel", also used by get_stty().
2359 * <BS> resulting <Del>
2360 * ^? ^H
2361 * not ^? ^?
2362 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 void
2364do_fixdel(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002365 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366{
2367 char_u *p;
2368
2369 p = find_termcode((char_u *)"kb");
2370 add_termcode((char_u *)"kD", p != NULL
2371 && *p == DEL ? (char_u *)CTRL_H_STR : DEL_STR, FALSE);
2372}
2373
2374 void
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00002375print_line_no_prefix(lnum, use_number, list)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 linenr_T lnum;
2377 int use_number;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00002378 int list;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379{
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002380 char_u numbuf[30];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381
2382 if (curwin->w_p_nu || use_number)
2383 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00002384 vim_snprintf((char *)numbuf, sizeof(numbuf),
2385 "%*ld ", number_width(curwin), (long)lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386 msg_puts_attr(numbuf, hl_attr(HLF_N)); /* Highlight line nrs */
2387 }
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00002388 msg_prt_line(ml_get(lnum), list);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389}
2390
2391/*
2392 * Print a text line. Also in silent mode ("ex -s").
2393 */
2394 void
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00002395print_line(lnum, use_number, list)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 linenr_T lnum;
2397 int use_number;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00002398 int list;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399{
2400 int save_silent = silent_mode;
2401
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 msg_start();
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00002403 silent_mode = FALSE;
2404 info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
2405 print_line_no_prefix(lnum, use_number, list);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 if (save_silent)
2407 {
2408 msg_putchar('\n');
2409 cursor_on(); /* msg_start() switches it off */
2410 out_flush();
2411 silent_mode = save_silent;
2412 }
Bram Moolenaar65b9a6a2009-02-04 12:14:51 +00002413 info_message = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414}
2415
2416/*
2417 * ":file[!] [fname]".
2418 */
2419 void
2420ex_file(eap)
2421 exarg_T *eap;
2422{
2423 char_u *fname, *sfname, *xfname;
2424 buf_T *buf;
2425
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002426 /* ":0file" removes the file name. Check for illegal uses ":3file",
2427 * "0file name", etc. */
2428 if (eap->addr_count > 0
2429 && (*eap->arg != NUL
2430 || eap->line2 > 0
2431 || eap->addr_count > 1))
2432 {
2433 EMSG(_(e_invarg));
2434 return;
2435 }
2436
2437 if (*eap->arg != NUL || eap->addr_count == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 {
2439#ifdef FEAT_AUTOCMD
2440 buf = curbuf;
2441 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
2442 /* buffer changed, don't change name now */
2443 if (buf != curbuf)
2444 return;
2445# ifdef FEAT_EVAL
2446 if (aborting()) /* autocmds may abort script processing */
2447 return;
2448# endif
2449#endif
2450 /*
2451 * The name of the current buffer will be changed.
2452 * A new (unlisted) buffer entry needs to be made to hold the old file
2453 * name, which will become the alternate file name.
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002454 * But don't set the alternate file name if the buffer didn't have a
2455 * name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 */
2457 fname = curbuf->b_ffname;
2458 sfname = curbuf->b_sfname;
2459 xfname = curbuf->b_fname;
2460 curbuf->b_ffname = NULL;
2461 curbuf->b_sfname = NULL;
2462 if (setfname(curbuf, eap->arg, NULL, TRUE) == FAIL)
2463 {
2464 curbuf->b_ffname = fname;
2465 curbuf->b_sfname = sfname;
2466 return;
2467 }
2468 curbuf->b_flags |= BF_NOTEDITED;
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002469 if (xfname != NULL && *xfname != NUL)
2470 {
2471 buf = buflist_new(fname, xfname, curwin->w_cursor.lnum, 0);
2472 if (buf != NULL && !cmdmod.keepalt)
2473 curwin->w_alt_fnum = buf->b_fnum;
2474 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 vim_free(fname);
2476 vim_free(sfname);
2477#ifdef FEAT_AUTOCMD
2478 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
2479#endif
Bram Moolenaar498efdb2006-09-05 14:31:54 +00002480 /* Change directories when the 'acd' option is set. */
2481 DO_AUTOCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 }
2483 /* print full file name if :cd used */
2484 fileinfo(FALSE, FALSE, eap->forceit);
2485}
2486
2487/*
2488 * ":update".
2489 */
2490 void
2491ex_update(eap)
2492 exarg_T *eap;
2493{
2494 if (curbufIsChanged())
2495 (void)do_write(eap);
2496}
2497
2498/*
2499 * ":write" and ":saveas".
2500 */
2501 void
2502ex_write(eap)
2503 exarg_T *eap;
2504{
2505 if (eap->usefilter) /* input lines to shell command */
2506 do_bang(1, eap, FALSE, TRUE, FALSE);
2507 else
2508 (void)do_write(eap);
2509}
2510
2511/*
2512 * write current buffer to file 'eap->arg'
2513 * if 'eap->append' is TRUE, append to the file
2514 *
2515 * if *eap->arg == NUL write to current file
2516 *
2517 * return FAIL for failure, OK otherwise
2518 */
2519 int
2520do_write(eap)
2521 exarg_T *eap;
2522{
2523 int other;
2524 char_u *fname = NULL; /* init to shut up gcc */
2525 char_u *ffname;
2526 int retval = FAIL;
2527 char_u *free_fname = NULL;
2528#ifdef FEAT_BROWSE
2529 char_u *browse_file = NULL;
2530#endif
2531 buf_T *alt_buf = NULL;
2532
2533 if (not_writing()) /* check 'write' option */
2534 return FAIL;
2535
2536 ffname = eap->arg;
2537#ifdef FEAT_BROWSE
2538 if (cmdmod.browse)
2539 {
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002540 browse_file = do_browse(BROWSE_SAVE, (char_u *)_("Save As"), ffname,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 NULL, NULL, NULL, curbuf);
2542 if (browse_file == NULL)
2543 goto theend;
2544 ffname = browse_file;
2545 }
2546#endif
2547 if (*ffname == NUL)
2548 {
2549 if (eap->cmdidx == CMD_saveas)
2550 {
2551 EMSG(_(e_argreq));
2552 goto theend;
2553 }
2554 other = FALSE;
2555 }
2556 else
2557 {
2558 fname = ffname;
2559 free_fname = fix_fname(ffname);
2560 /*
2561 * When out-of-memory, keep unexpanded file name, because we MUST be
2562 * able to write the file in this situation.
2563 */
2564 if (free_fname != NULL)
2565 ffname = free_fname;
2566 other = otherfile(ffname);
2567 }
2568
2569 /*
2570 * If we have a new file, put its name in the list of alternate file names.
2571 */
2572 if (other)
2573 {
2574 if (vim_strchr(p_cpo, CPO_ALTWRITE) != NULL
2575 || eap->cmdidx == CMD_saveas)
2576 alt_buf = setaltfname(ffname, fname, (linenr_T)1);
2577 else
2578 alt_buf = buflist_findname(ffname);
2579 if (alt_buf != NULL && alt_buf->b_ml.ml_mfp != NULL)
2580 {
2581 /* Overwriting a file that is loaded in another buffer is not a
2582 * good idea. */
Bram Moolenaar0e4d8772005-06-07 21:12:49 +00002583 EMSG(_(e_bufloaded));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 goto theend;
2585 }
2586 }
2587
2588 /*
2589 * Writing to the current file is not allowed in readonly mode
2590 * and a file name is required.
2591 * "nofile" and "nowrite" buffers cannot be written implicitly either.
2592 */
2593 if (!other && (
2594#ifdef FEAT_QUICKFIX
2595 bt_dontwrite_msg(curbuf) ||
2596#endif
2597 check_fname() == FAIL || check_readonly(&eap->forceit, curbuf)))
2598 goto theend;
2599
2600 if (!other)
2601 {
2602 ffname = curbuf->b_ffname;
2603 fname = curbuf->b_fname;
2604 /*
2605 * Not writing the whole file is only allowed with '!'.
2606 */
2607 if ( (eap->line1 != 1
2608 || eap->line2 != curbuf->b_ml.ml_line_count)
2609 && !eap->forceit
2610 && !eap->append
2611 && !p_wa)
2612 {
2613#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2614 if (p_confirm || cmdmod.confirm)
2615 {
2616 if (vim_dialog_yesno(VIM_QUESTION, NULL,
2617 (char_u *)_("Write partial file?"), 2) != VIM_YES)
2618 goto theend;
2619 eap->forceit = TRUE;
2620 }
2621 else
2622#endif
2623 {
2624 EMSG(_("E140: Use ! to write partial buffer"));
2625 goto theend;
2626 }
2627 }
2628 }
2629
2630 if (check_overwrite(eap, curbuf, fname, ffname, other) == OK)
2631 {
2632 if (eap->cmdidx == CMD_saveas && alt_buf != NULL)
2633 {
2634#ifdef FEAT_AUTOCMD
2635 buf_T *was_curbuf = curbuf;
2636
2637 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar269ec652004-07-29 08:43:53 +00002638 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, alt_buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002639# ifdef FEAT_EVAL
2640 if (curbuf != was_curbuf || aborting())
2641# else
2642 if (curbuf != was_curbuf)
2643# endif
2644 {
2645 /* buffer changed, don't change name now */
2646 retval = FAIL;
2647 goto theend;
2648 }
2649#endif
2650 /* Exchange the file names for the current and the alternate
2651 * buffer. This makes it look like we are now editing the buffer
2652 * under the new name. Must be done before buf_write(), because
2653 * if there is no file name and 'cpo' contains 'F', it will set
2654 * the file name. */
2655 fname = alt_buf->b_fname;
2656 alt_buf->b_fname = curbuf->b_fname;
2657 curbuf->b_fname = fname;
2658 fname = alt_buf->b_ffname;
2659 alt_buf->b_ffname = curbuf->b_ffname;
2660 curbuf->b_ffname = fname;
2661 fname = alt_buf->b_sfname;
2662 alt_buf->b_sfname = curbuf->b_sfname;
2663 curbuf->b_sfname = fname;
2664 buf_name_changed(curbuf);
2665#ifdef FEAT_AUTOCMD
2666 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
Bram Moolenaar269ec652004-07-29 08:43:53 +00002667 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, alt_buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668 if (!alt_buf->b_p_bl)
2669 {
2670 alt_buf->b_p_bl = TRUE;
2671 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, alt_buf);
2672 }
2673# ifdef FEAT_EVAL
2674 if (curbuf != was_curbuf || aborting())
2675# else
2676 if (curbuf != was_curbuf)
2677# endif
2678 {
2679 /* buffer changed, don't write the file */
2680 retval = FAIL;
2681 goto theend;
2682 }
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002683
2684 /* If 'filetype' was empty try detecting it now. */
2685 if (*curbuf->b_p_ft == NUL)
2686 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002687 if (au_has_group((char_u *)"filetypedetect"))
2688 (void)do_doautocmd((char_u *)"filetypedetect BufRead",
2689 TRUE);
Bram Moolenaara3227e22006-03-08 21:32:40 +00002690 do_modelines(0);
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002691 }
Bram Moolenaarf666f0e2010-11-24 17:59:32 +01002692
2693 /* Autocommands may have changed buffer names, esp. when
2694 * 'autochdir' is set. */
2695 fname = curbuf->b_sfname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696#endif
2697 }
2698
2699 retval = buf_write(curbuf, ffname, fname, eap->line1, eap->line2,
2700 eap, eap->append, eap->forceit, TRUE, FALSE);
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002701
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002702 /* After ":saveas fname" reset 'readonly'. */
Bram Moolenaar498efdb2006-09-05 14:31:54 +00002703 if (eap->cmdidx == CMD_saveas)
2704 {
2705 if (retval == OK)
Bram Moolenaar4352f132009-02-11 15:03:45 +00002706 {
Bram Moolenaar498efdb2006-09-05 14:31:54 +00002707 curbuf->b_p_ro = FALSE;
Bram Moolenaar4352f132009-02-11 15:03:45 +00002708#ifdef FEAT_WINDOWS
2709 redraw_tabline = TRUE;
2710#endif
2711 }
Bram Moolenaar498efdb2006-09-05 14:31:54 +00002712 /* Change directories when the 'acd' option is set. */
2713 DO_AUTOCHDIR
2714 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 }
2716
2717theend:
2718#ifdef FEAT_BROWSE
2719 vim_free(browse_file);
2720#endif
2721 vim_free(free_fname);
2722 return retval;
2723}
2724
2725/*
2726 * Check if it is allowed to overwrite a file. If b_flags has BF_NOTEDITED,
2727 * BF_NEW or BF_READERR, check for overwriting current file.
2728 * May set eap->forceit if a dialog says it's OK to overwrite.
2729 * Return OK if it's OK, FAIL if it is not.
2730 */
Bram Moolenaar8218f602012-04-25 17:32:18 +02002731 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732check_overwrite(eap, buf, fname, ffname, other)
2733 exarg_T *eap;
2734 buf_T *buf;
2735 char_u *fname; /* file name to be used (can differ from
2736 buf->ffname) */
2737 char_u *ffname; /* full path version of fname */
2738 int other; /* writing under other name */
2739{
2740 /*
2741 * write to other file or b_flags set or not writing the whole file:
2742 * overwriting only allowed with '!'
2743 */
2744 if ( (other
2745 || (buf->b_flags & BF_NOTEDITED)
2746 || ((buf->b_flags & BF_NEW)
2747 && vim_strchr(p_cpo, CPO_OVERNEW) == NULL)
2748 || (buf->b_flags & BF_READERR))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749 && !p_wa
Bram Moolenaar11717bb2007-12-08 21:21:18 +00002750#ifdef FEAT_QUICKFIX
2751 && !bt_nofile(buf)
2752#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753 && vim_fexists(ffname))
2754 {
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002755 if (!eap->forceit && !eap->append)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 {
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002757#ifdef UNIX
Bram Moolenaar0ac93792006-01-21 22:16:51 +00002758 /* with UNIX it is possible to open a directory */
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002759 if (mch_isdir(ffname))
2760 {
2761 EMSG2(_(e_isadir2), ffname);
2762 return FAIL;
2763 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764#endif
2765#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002766 if (p_confirm || cmdmod.confirm)
2767 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002768 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002770 dialog_msg(buff, _("Overwrite existing file \"%s\"?"), fname);
2771 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES)
2772 return FAIL;
2773 eap->forceit = TRUE;
2774 }
2775 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776#endif
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002777 {
2778 EMSG(_(e_exists));
2779 return FAIL;
2780 }
2781 }
2782
2783 /* For ":w! filename" check that no swap file exists for "filename". */
2784 if (other && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002786 char_u *dir;
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002787 char_u *p;
2788 int r;
2789 char_u *swapname;
2790
2791 /* We only try the first entry in 'directory', without checking if
2792 * it's writable. If the "." directory is not writable the write
2793 * will probably fail anyway.
2794 * Use 'shortname' of the current buffer, since there is no buffer
2795 * for the written file. */
2796 if (*p_dir == NUL)
Bram Moolenaard9462e32011-04-11 21:35:11 +02002797 {
2798 dir = alloc(5);
2799 if (dir == NULL)
2800 return FAIL;
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002801 STRCPY(dir, ".");
Bram Moolenaard9462e32011-04-11 21:35:11 +02002802 }
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002803 else
2804 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002805 dir = alloc(MAXPATHL);
2806 if (dir == NULL)
2807 return FAIL;
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002808 p = p_dir;
2809 copy_option_part(&p, dir, MAXPATHL, ",");
2810 }
2811 swapname = makeswapname(fname, ffname, curbuf, dir);
Bram Moolenaard9462e32011-04-11 21:35:11 +02002812 vim_free(dir);
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002813 r = vim_fexists(swapname);
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002814 if (r)
2815 {
2816#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2817 if (p_confirm || cmdmod.confirm)
2818 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002819 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002820
2821 dialog_msg(buff,
2822 _("Swap file \"%s\" exists, overwrite anyway?"),
2823 swapname);
2824 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2)
2825 != VIM_YES)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002826 {
2827 vim_free(swapname);
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002828 return FAIL;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002829 }
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002830 eap->forceit = TRUE;
2831 }
2832 else
2833#endif
2834 {
2835 EMSG2(_("E768: Swap file exists: %s (:silent! overrides)"),
2836 swapname);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002837 vim_free(swapname);
Bram Moolenaar04a09c12005-08-01 22:02:32 +00002838 return FAIL;
2839 }
2840 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002841 vim_free(swapname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002842 }
2843 }
2844 return OK;
2845}
2846
2847/*
2848 * Handle ":wnext", ":wNext" and ":wprevious" commands.
2849 */
2850 void
2851ex_wnext(eap)
2852 exarg_T *eap;
2853{
2854 int i;
2855
2856 if (eap->cmd[1] == 'n')
2857 i = curwin->w_arg_idx + (int)eap->line2;
2858 else
2859 i = curwin->w_arg_idx - (int)eap->line2;
2860 eap->line1 = 1;
2861 eap->line2 = curbuf->b_ml.ml_line_count;
2862 if (do_write(eap) != FAIL)
2863 do_argfile(eap, i);
2864}
2865
2866/*
2867 * ":wall", ":wqall" and ":xall": Write all changed files (and exit).
2868 */
2869 void
2870do_wqall(eap)
2871 exarg_T *eap;
2872{
2873 buf_T *buf;
2874 int error = 0;
2875 int save_forceit = eap->forceit;
2876
2877 if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall)
2878 exiting = TRUE;
2879
2880 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2881 {
2882 if (bufIsChanged(buf))
2883 {
2884 /*
2885 * Check if there is a reason the buffer cannot be written:
2886 * 1. if the 'write' option is set
2887 * 2. if there is no file name (even after browsing)
2888 * 3. if the 'readonly' is set (even after a dialog)
2889 * 4. if overwriting is allowed (even after a dialog)
2890 */
2891 if (not_writing())
2892 {
2893 ++error;
2894 break;
2895 }
2896#ifdef FEAT_BROWSE
2897 /* ":browse wall": ask for file name if there isn't one */
2898 if (buf->b_ffname == NULL && cmdmod.browse)
2899 browse_save_fname(buf);
2900#endif
2901 if (buf->b_ffname == NULL)
2902 {
2903 EMSGN(_("E141: No file name for buffer %ld"), (long)buf->b_fnum);
2904 ++error;
2905 }
2906 else if (check_readonly(&eap->forceit, buf)
2907 || check_overwrite(eap, buf, buf->b_fname, buf->b_ffname,
2908 FALSE) == FAIL)
2909 {
2910 ++error;
2911 }
2912 else
2913 {
2914 if (buf_write_all(buf, eap->forceit) == FAIL)
2915 ++error;
2916#ifdef FEAT_AUTOCMD
2917 /* an autocommand may have deleted the buffer */
2918 if (!buf_valid(buf))
2919 buf = firstbuf;
2920#endif
2921 }
2922 eap->forceit = save_forceit; /* check_overwrite() may set it */
2923 }
2924 }
2925 if (exiting)
2926 {
2927 if (!error)
2928 getout(0); /* exit Vim */
2929 not_exiting();
2930 }
2931}
2932
2933/*
2934 * Check the 'write' option.
2935 * Return TRUE and give a message when it's not st.
2936 */
2937 int
2938not_writing()
2939{
2940 if (p_write)
2941 return FALSE;
2942 EMSG(_("E142: File not written: Writing is disabled by 'write' option"));
2943 return TRUE;
2944}
2945
2946/*
Bram Moolenaar5386a122007-06-28 20:02:32 +00002947 * Check if a buffer is read-only (either 'readonly' option is set or file is
2948 * read-only). Ask for overruling in a dialog. Return TRUE and give an error
2949 * message when the buffer is readonly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 */
2951 static int
2952check_readonly(forceit, buf)
2953 int *forceit;
2954 buf_T *buf;
2955{
Bram Moolenaar5386a122007-06-28 20:02:32 +00002956 struct stat st;
2957
2958 /* Handle a file being readonly when the 'readonly' option is set or when
2959 * the file exists and permissions are read-only.
2960 * We will send 0777 to check_file_readonly(), as the "perm" variable is
2961 * important for device checks but not here. */
2962 if (!*forceit && (buf->b_p_ro
2963 || (mch_stat((char *)buf->b_ffname, &st) >= 0
2964 && check_file_readonly(buf->b_ffname, 0777))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965 {
2966#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2967 if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL)
2968 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002969 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002970
Bram Moolenaar5386a122007-06-28 20:02:32 +00002971 if (buf->b_p_ro)
2972 dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
2973 buf->b_fname);
2974 else
2975 dialog_msg(buff, _("File permissions of \"%s\" are read-only.\nIt may still be possible to write it.\nDo you wish to try?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002976 buf->b_fname);
2977
2978 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES)
2979 {
2980 /* Set forceit, to force the writing of a readonly file */
2981 *forceit = TRUE;
2982 return FALSE;
2983 }
2984 else
2985 return TRUE;
2986 }
2987 else
2988#endif
Bram Moolenaar5386a122007-06-28 20:02:32 +00002989 if (buf->b_p_ro)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 EMSG(_(e_readonly));
Bram Moolenaar5386a122007-06-28 20:02:32 +00002991 else
2992 EMSG2(_("E505: \"%s\" is read-only (add ! to override)"),
2993 buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002994 return TRUE;
2995 }
Bram Moolenaar5386a122007-06-28 20:02:32 +00002996
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997 return FALSE;
2998}
2999
3000/*
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00003001 * Try to abandon current file and edit a new or existing file.
3002 * 'fnum' is the number of the file, if zero use ffname/sfname.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003 *
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00003004 * Return 1 for "normal" error, 2 for "not written" error, 0 for success
Bram Moolenaareb1b6792007-08-21 13:29:28 +00003005 * -1 for successfully opening another file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 * 'lnum' is the line number for the cursor in the new file (if non-zero).
3007 */
3008 int
3009getfile(fnum, ffname, sfname, setpm, lnum, forceit)
3010 int fnum;
3011 char_u *ffname;
3012 char_u *sfname;
3013 int setpm;
3014 linenr_T lnum;
3015 int forceit;
3016{
3017 int other;
3018 int retval;
3019 char_u *free_me = NULL;
3020
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00003021 if (text_locked())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 return 1;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003023#ifdef FEAT_AUTOCMD
3024 if (curbuf_locked())
3025 return 1;
3026#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003027
3028 if (fnum == 0)
3029 {
3030 /* make ffname full path, set sfname */
3031 fname_expand(curbuf, &ffname, &sfname);
3032 other = otherfile(ffname);
3033 free_me = ffname; /* has been allocated, free() later */
3034 }
3035 else
3036 other = (fnum != curbuf->b_fnum);
3037
3038 if (other)
3039 ++no_wait_return; /* don't wait for autowrite message */
3040 if (other && !forceit && curbuf->b_nwindows == 1 && !P_HID(curbuf)
3041 && curbufIsChanged() && autowrite(curbuf, forceit) == FAIL)
3042 {
3043#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
3044 if (p_confirm && p_write)
3045 dialog_changed(curbuf, FALSE);
3046 if (curbufIsChanged())
3047#endif
3048 {
3049 if (other)
3050 --no_wait_return;
3051 EMSG(_(e_nowrtmsg));
3052 retval = 2; /* file has been changed */
3053 goto theend;
3054 }
3055 }
3056 if (other)
3057 --no_wait_return;
3058 if (setpm)
3059 setpcmark();
3060 if (!other)
3061 {
3062 if (lnum != 0)
3063 curwin->w_cursor.lnum = lnum;
3064 check_cursor_lnum();
3065 beginline(BL_SOL | BL_FIX);
3066 retval = 0; /* it's in the same file */
3067 }
3068 else if (do_ecmd(fnum, ffname, sfname, NULL, lnum,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003069 (P_HID(curbuf) ? ECMD_HIDE : 0) + (forceit ? ECMD_FORCEIT : 0),
3070 curwin) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 retval = -1; /* opened another file */
3072 else
3073 retval = 1; /* error encountered */
3074
3075theend:
3076 vim_free(free_me);
3077 return retval;
3078}
3079
3080/*
3081 * start editing a new file
3082 *
3083 * fnum: file number; if zero use ffname/sfname
3084 * ffname: the file name
3085 * - full path if sfname used,
3086 * - any file name if sfname is NULL
3087 * - empty string to re-edit with the same file name (but may be
3088 * in a different directory)
3089 * - NULL to start an empty buffer
3090 * sfname: the short file name (or NULL)
3091 * eap: contains the command to be executed after loading the file and
3092 * forced 'ff' and 'fenc'
3093 * newlnum: if > 0: put cursor on this line number (if possible)
3094 * if ECMD_LASTL: use last position in loaded file
3095 * if ECMD_LAST: use last position in all files
3096 * if ECMD_ONE: use first line
3097 * flags:
3098 * ECMD_HIDE: if TRUE don't free the current buffer
3099 * ECMD_SET_HELP: set b_help flag of (new) buffer before opening file
3100 * ECMD_OLDBUF: use existing buffer if it exists
3101 * ECMD_FORCEIT: ! used for Ex command
3102 * ECMD_ADDBUF: don't edit, just add to buffer list
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003103 * oldwin: Should be "curwin" when editing a new buffer in the current
Bram Moolenaarcc448b32010-07-14 16:52:17 +02003104 * window, NULL when splitting the window first. When not NULL info
3105 * of the previous buffer for "oldwin" is stored.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106 *
3107 * return FAIL for failure, OK otherwise
3108 */
3109 int
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003110do_ecmd(fnum, ffname, sfname, eap, newlnum, flags, oldwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111 int fnum;
3112 char_u *ffname;
3113 char_u *sfname;
3114 exarg_T *eap; /* can be NULL! */
3115 linenr_T newlnum;
3116 int flags;
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003117 win_T *oldwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118{
3119 int other_file; /* TRUE if editing another file */
3120 int oldbuf; /* TRUE if using existing buffer */
3121#ifdef FEAT_AUTOCMD
3122 int auto_buf = FALSE; /* TRUE if autocommands brought us
3123 into the buffer unexpectedly */
3124 char_u *new_name = NULL;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003125 int did_set_swapcommand = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126#endif
3127 buf_T *buf;
3128#if defined(FEAT_AUTOCMD) || defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
3129 buf_T *old_curbuf = curbuf;
3130#endif
3131 char_u *free_fname = NULL;
3132#ifdef FEAT_BROWSE
3133 char_u *browse_file = NULL;
3134#endif
3135 int retval = FAIL;
3136 long n;
3137 linenr_T lnum;
3138 linenr_T topline = 0;
3139 int newcol = -1;
3140 int solcol = -1;
3141 pos_T *pos;
3142#ifdef FEAT_SUN_WORKSHOP
3143 char_u *cp;
3144#endif
3145 char_u *command = NULL;
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00003146#ifdef FEAT_SPELL
3147 int did_get_winopts = FALSE;
3148#endif
Bram Moolenaar59f931e2010-07-24 20:27:03 +02003149 int readfile_flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150
3151 if (eap != NULL)
3152 command = eap->do_ecmd_cmd;
3153
3154 if (fnum != 0)
3155 {
3156 if (fnum == curbuf->b_fnum) /* file is already being edited */
3157 return OK; /* nothing to do */
3158 other_file = TRUE;
3159 }
3160 else
3161 {
3162#ifdef FEAT_BROWSE
3163 if (cmdmod.browse)
3164 {
Bram Moolenaar15bfa092008-07-24 16:45:38 +00003165# ifdef FEAT_AUTOCMD
Bram Moolenaar0be6e642005-08-04 21:32:22 +00003166 if (
Bram Moolenaar15bfa092008-07-24 16:45:38 +00003167# ifdef FEAT_GUI
Bram Moolenaar0be6e642005-08-04 21:32:22 +00003168 !gui.in_use &&
Bram Moolenaar15bfa092008-07-24 16:45:38 +00003169# endif
Bram Moolenaar0be6e642005-08-04 21:32:22 +00003170 au_has_group((char_u *)"FileExplorer"))
3171 {
3172 /* No browsing supported but we do have the file explorer:
3173 * Edit the directory. */
3174 if (ffname == NULL || !mch_isdir(ffname))
3175 ffname = (char_u *)".";
3176 }
3177 else
Bram Moolenaar15bfa092008-07-24 16:45:38 +00003178# endif
Bram Moolenaar0be6e642005-08-04 21:32:22 +00003179 {
3180 browse_file = do_browse(0, (char_u *)_("Edit File"), ffname,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181 NULL, NULL, NULL, curbuf);
Bram Moolenaar0be6e642005-08-04 21:32:22 +00003182 if (browse_file == NULL)
3183 goto theend;
3184 ffname = browse_file;
3185 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 }
3187#endif
3188 /* if no short name given, use ffname for short name */
3189 if (sfname == NULL)
3190 sfname = ffname;
3191#ifdef USE_FNAME_CASE
3192# ifdef USE_LONG_FNAME
3193 if (USE_LONG_FNAME)
3194# endif
Bram Moolenaar342337a2005-07-21 21:11:17 +00003195 if (sfname != NULL)
3196 fname_case(sfname, 0); /* set correct case for sfname */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197#endif
3198
3199#ifdef FEAT_LISTCMDS
3200 if ((flags & ECMD_ADDBUF) && (ffname == NULL || *ffname == NUL))
3201 goto theend;
3202#endif
3203
3204 if (ffname == NULL)
3205 other_file = TRUE;
3206 /* there is no file name */
3207 else if (*ffname == NUL && curbuf->b_ffname == NULL)
3208 other_file = FALSE;
3209 else
3210 {
3211 if (*ffname == NUL) /* re-edit with same file name */
3212 {
3213 ffname = curbuf->b_ffname;
3214 sfname = curbuf->b_fname;
3215 }
3216 free_fname = fix_fname(ffname); /* may expand to full path name */
3217 if (free_fname != NULL)
3218 ffname = free_fname;
3219 other_file = otherfile(ffname);
3220#ifdef FEAT_SUN_WORKSHOP
3221 if (usingSunWorkShop && p_acd
3222 && (cp = vim_strrchr(sfname, '/')) != NULL)
3223 sfname = ++cp;
3224#endif
3225 }
3226 }
3227
3228 /*
3229 * if the file was changed we may not be allowed to abandon it
3230 * - if we are going to re-edit the same file
3231 * - or if we are the only window on this file and if ECMD_HIDE is FALSE
3232 */
3233 if ( ((!other_file && !(flags & ECMD_OLDBUF))
3234 || (curbuf->b_nwindows == 1
3235 && !(flags & (ECMD_HIDE | ECMD_ADDBUF))))
3236 && check_changed(curbuf, p_awa, !other_file,
3237 (flags & ECMD_FORCEIT), FALSE))
3238 {
3239 if (fnum == 0 && other_file && ffname != NULL)
3240 (void)setaltfname(ffname, sfname, newlnum < 0 ? 0 : newlnum);
3241 goto theend;
3242 }
3243
3244#ifdef FEAT_VISUAL
3245 /*
3246 * End Visual mode before switching to another buffer, so the text can be
3247 * copied into the GUI selection buffer.
3248 */
3249 reset_VIsual();
3250#endif
3251
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003252#ifdef FEAT_AUTOCMD
3253 if ((command != NULL || newlnum > (linenr_T)0)
3254 && *get_vim_var_str(VV_SWAPCOMMAND) == NUL)
3255 {
3256 int len;
3257 char_u *p;
3258
3259 /* Set v:swapcommand for the SwapExists autocommands. */
3260 if (command != NULL)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003261 len = (int)STRLEN(command) + 3;
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003262 else
3263 len = 30;
3264 p = alloc((unsigned)len);
3265 if (p != NULL)
3266 {
3267 if (command != NULL)
3268 vim_snprintf((char *)p, len, ":%s\r", command);
3269 else
3270 vim_snprintf((char *)p, len, "%ldG", (long)newlnum);
3271 set_vim_var_string(VV_SWAPCOMMAND, p, -1);
3272 did_set_swapcommand = TRUE;
3273 vim_free(p);
3274 }
3275 }
3276#endif
3277
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 /*
3279 * If we are starting to edit another file, open a (new) buffer.
3280 * Otherwise we re-use the current buffer.
3281 */
3282 if (other_file)
3283 {
3284#ifdef FEAT_LISTCMDS
3285 if (!(flags & ECMD_ADDBUF))
3286#endif
3287 {
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003288 if (!cmdmod.keepalt)
3289 curwin->w_alt_fnum = curbuf->b_fnum;
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003290 if (oldwin != NULL)
3291 buflist_altfpos(oldwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 }
3293
3294 if (fnum)
3295 buf = buflist_findnr(fnum);
3296 else
3297 {
3298#ifdef FEAT_LISTCMDS
3299 if (flags & ECMD_ADDBUF)
3300 {
3301 linenr_T tlnum = 1L;
3302
3303 if (command != NULL)
3304 {
3305 tlnum = atol((char *)command);
3306 if (tlnum <= 0)
3307 tlnum = 1L;
3308 }
3309 (void)buflist_new(ffname, sfname, tlnum, BLN_LISTED);
3310 goto theend;
3311 }
3312#endif
3313 buf = buflist_new(ffname, sfname, 0L,
3314 BLN_CURBUF | ((flags & ECMD_SET_HELP) ? 0 : BLN_LISTED));
3315 }
3316 if (buf == NULL)
3317 goto theend;
3318 if (buf->b_ml.ml_mfp == NULL) /* no memfile yet */
3319 {
3320 oldbuf = FALSE;
3321 buf->b_nwindows = 0;
3322 }
3323 else /* existing memfile */
3324 {
3325 oldbuf = TRUE;
3326 (void)buf_check_timestamp(buf, FALSE);
3327 /* Check if autocommands made buffer invalid or changed the current
3328 * buffer. */
3329 if (!buf_valid(buf)
3330#ifdef FEAT_AUTOCMD
3331 || curbuf != old_curbuf
3332#endif
3333 )
3334 goto theend;
3335#ifdef FEAT_EVAL
3336 if (aborting()) /* autocmds may abort script processing */
3337 goto theend;
3338#endif
3339 }
3340
3341 /* May jump to last used line number for a loaded buffer or when asked
3342 * for explicitly */
3343 if ((oldbuf && newlnum == ECMD_LASTL) || newlnum == ECMD_LAST)
3344 {
3345 pos = buflist_findfpos(buf);
3346 newlnum = pos->lnum;
3347 solcol = pos->col;
3348 }
3349
3350 /*
3351 * Make the (new) buffer the one used by the current window.
3352 * If the old buffer becomes unused, free it if ECMD_HIDE is FALSE.
3353 * If the current buffer was empty and has no file name, curbuf
3354 * is returned by buflist_new().
3355 */
3356 if (buf != curbuf)
3357 {
3358#ifdef FEAT_AUTOCMD
3359 /*
3360 * Be careful: The autocommands may delete any buffer and change
3361 * the current buffer.
3362 * - If the buffer we are going to edit is deleted, give up.
3363 * - If the current buffer is deleted, prefer to load the new
3364 * buffer when loading a buffer is required. This avoids
3365 * loading another buffer which then must be closed again.
3366 * - If we ended up in the new buffer already, need to skip a few
3367 * things, set auto_buf.
3368 */
3369 if (buf->b_fname != NULL)
3370 new_name = vim_strsave(buf->b_fname);
3371 au_new_curbuf = buf;
3372 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
3373 if (!buf_valid(buf)) /* new buffer has been deleted */
3374 {
3375 delbuf_msg(new_name); /* frees new_name */
3376 goto theend;
3377 }
3378# ifdef FEAT_EVAL
3379 if (aborting()) /* autocmds may abort script processing */
3380 {
3381 vim_free(new_name);
3382 goto theend;
3383 }
3384# endif
3385 if (buf == curbuf) /* already in new buffer */
3386 auto_buf = TRUE;
3387 else
3388 {
3389 if (curbuf == old_curbuf)
3390#endif
3391 buf_copy_options(buf, BCO_ENTER);
3392
3393 /* close the link to the current buffer */
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003394 u_sync(FALSE);
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003395 close_buffer(oldwin, curbuf,
Bram Moolenaar42ec6562012-02-22 14:58:37 +01003396 (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397
3398#ifdef FEAT_AUTOCMD
Bram Moolenaarfc573802011-12-30 15:01:59 +01003399 /* Autocommands may open a new window and leave oldwin open
3400 * which leads to crashes since the above call sets
3401 * oldwin->w_buffer to NULL. */
3402 if (curwin != oldwin && oldwin != aucmd_win
3403 && win_valid(oldwin) && oldwin->w_buffer == NULL)
3404 win_close(oldwin, FALSE);
3405
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406# ifdef FEAT_EVAL
3407 if (aborting()) /* autocmds may abort script processing */
3408 {
3409 vim_free(new_name);
3410 goto theend;
3411 }
3412# endif
3413 /* Be careful again, like above. */
3414 if (!buf_valid(buf)) /* new buffer has been deleted */
3415 {
3416 delbuf_msg(new_name); /* frees new_name */
3417 goto theend;
3418 }
3419 if (buf == curbuf) /* already in new buffer */
3420 auto_buf = TRUE;
3421 else
3422#endif
3423 {
Bram Moolenaar860cae12010-06-05 23:22:07 +02003424#ifdef FEAT_SYN_HL
3425 /*
3426 * <VN> We could instead free the synblock
3427 * and re-attach to buffer, perhaps.
3428 */
3429 if (curwin->w_s == &(curwin->w_buffer->b_s))
Bram Moolenaar720ce532012-04-25 12:57:28 +02003430 curwin->w_s = &(buf->b_s);
Bram Moolenaar860cae12010-06-05 23:22:07 +02003431#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003432 curwin->w_buffer = buf;
3433 curbuf = buf;
3434 ++curbuf->b_nwindows;
3435 /* set 'fileformat' */
3436 if (*p_ffs && !oldbuf)
3437 set_fileformat(default_fileformat(), OPT_LOCAL);
3438 }
3439
3440 /* May get the window options from the last time this buffer
3441 * was in this window (or another window). If not used
3442 * before, reset the local window options to the global
3443 * values. Also restores old folding stuff. */
Bram Moolenaarb1269f12007-06-19 09:51:25 +00003444 get_winopts(curbuf);
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00003445#ifdef FEAT_SPELL
3446 did_get_winopts = TRUE;
3447#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448
3449#ifdef FEAT_AUTOCMD
3450 }
3451 vim_free(new_name);
3452 au_new_curbuf = NULL;
3453#endif
3454 }
3455 else
3456 ++curbuf->b_nwindows;
3457
3458 curwin->w_pcmark.lnum = 1;
3459 curwin->w_pcmark.col = 0;
3460 }
3461 else /* !other_file */
3462 {
3463 if (
3464#ifdef FEAT_LISTCMDS
3465 (flags & ECMD_ADDBUF) ||
3466#endif
3467 check_fname() == FAIL)
3468 goto theend;
3469 oldbuf = (flags & ECMD_OLDBUF);
3470 }
3471
3472 if ((flags & ECMD_SET_HELP) || keep_help_flag)
3473 {
3474 char_u *p;
3475
3476 curbuf->b_help = TRUE;
3477#ifdef FEAT_QUICKFIX
3478 set_string_option_direct((char_u *)"buftype", -1,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003479 (char_u *)"help", OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480#endif
3481
3482 /*
3483 * Always set these options after jumping to a help tag, because the
3484 * user may have an autocommand that gets in the way.
3485 * Accept all ASCII chars for keywords, except ' ', '*', '"', '|', and
3486 * latin1 word characters (for translated help files).
3487 * Only set it when needed, buf_init_chartab() is some work.
3488 */
3489 p =
3490#ifdef EBCDIC
3491 (char_u *)"65-255,^*,^|,^\"";
3492#else
3493 (char_u *)"!-~,^*,^|,^\",192-255";
3494#endif
3495 if (STRCMP(curbuf->b_p_isk, p) != 0)
3496 {
3497 set_string_option_direct((char_u *)"isk", -1, p,
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003498 OPT_FREE|OPT_LOCAL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 check_buf_options(curbuf);
3500 (void)buf_init_chartab(curbuf, FALSE);
3501 }
3502
3503 curbuf->b_p_ts = 8; /* 'tabstop' is 8 */
3504 curwin->w_p_list = FALSE; /* no list mode */
3505
3506 curbuf->b_p_ma = FALSE; /* not modifiable */
3507 curbuf->b_p_bin = FALSE; /* reset 'bin' before reading file */
3508 curwin->w_p_nu = 0; /* no line numbers */
Bram Moolenaar64486672010-05-16 15:46:46 +02003509 curwin->w_p_rnu = 0; /* no relative line numbers */
Bram Moolenaar3368ea22010-09-21 16:56:35 +02003510 RESET_BINDING(curwin); /* no scroll or cursor binding */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511#ifdef FEAT_ARABIC
3512 curwin->w_p_arab = FALSE; /* no arabic mode */
3513#endif
3514#ifdef FEAT_RIGHTLEFT
3515 curwin->w_p_rl = FALSE; /* help window is left-to-right */
3516#endif
3517#ifdef FEAT_FOLDING
3518 curwin->w_p_fen = FALSE; /* No folding in the help window */
3519#endif
3520#ifdef FEAT_DIFF
3521 curwin->w_p_diff = FALSE; /* No 'diff' */
3522#endif
Bram Moolenaara1956f62006-03-12 22:18:00 +00003523#ifdef FEAT_SPELL
Bram Moolenaar9a50b1b2005-06-27 22:48:21 +00003524 curwin->w_p_spell = FALSE; /* No spell checking */
3525#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526
3527#ifdef FEAT_AUTOCMD
3528 buf = curbuf;
3529#endif
3530 set_buflisted(FALSE);
3531 }
3532 else
3533 {
3534#ifdef FEAT_AUTOCMD
3535 buf = curbuf;
3536#endif
3537 /* Don't make a buffer listed if it's a help buffer. Useful when
3538 * using CTRL-O to go back to a help file. */
3539 if (!curbuf->b_help)
3540 set_buflisted(TRUE);
3541 }
3542
3543#ifdef FEAT_AUTOCMD
3544 /* If autocommands change buffers under our fingers, forget about
3545 * editing the file. */
3546 if (buf != curbuf)
3547 goto theend;
3548# ifdef FEAT_EVAL
3549 if (aborting()) /* autocmds may abort script processing */
3550 goto theend;
3551# endif
3552
3553 /* Since we are starting to edit a file, consider the filetype to be
3554 * unset. Helps for when an autocommand changes files and expects syntax
3555 * highlighting to work in the other file. */
3556 did_filetype = FALSE;
3557#endif
3558
3559/*
3560 * other_file oldbuf
3561 * FALSE FALSE re-edit same file, buffer is re-used
3562 * FALSE TRUE re-edit same file, nothing changes
3563 * TRUE FALSE start editing new file, new buffer
3564 * TRUE TRUE start editing in existing buffer (nothing to do)
3565 */
3566 if (!other_file && !oldbuf) /* re-use the buffer */
3567 {
3568 set_last_cursor(curwin); /* may set b_last_cursor */
3569 if (newlnum == ECMD_LAST || newlnum == ECMD_LASTL)
3570 {
3571 newlnum = curwin->w_cursor.lnum;
3572 solcol = curwin->w_cursor.col;
3573 }
3574#ifdef FEAT_AUTOCMD
3575 buf = curbuf;
3576 if (buf->b_fname != NULL)
3577 new_name = vim_strsave(buf->b_fname);
3578 else
3579 new_name = NULL;
3580#endif
Bram Moolenaar59f931e2010-07-24 20:27:03 +02003581 if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)
3582 {
3583 /* Save all the text, so that the reload can be undone.
3584 * Sync first so that this is a separate undo-able action. */
3585 u_sync(FALSE);
3586 if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE)
3587 == FAIL)
3588 goto theend;
3589 u_unchanged(curbuf);
3590 buf_freeall(curbuf, BFA_KEEP_UNDO);
3591
3592 /* tell readfile() not to clear or reload undo info */
3593 readfile_flags = READ_KEEP_UNDO;
3594 }
3595 else
3596 buf_freeall(curbuf, 0); /* free all things for buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597#ifdef FEAT_AUTOCMD
3598 /* If autocommands deleted the buffer we were going to re-edit, give
3599 * up and jump to the end. */
3600 if (!buf_valid(buf))
3601 {
3602 delbuf_msg(new_name); /* frees new_name */
3603 goto theend;
3604 }
3605 vim_free(new_name);
3606
3607 /* If autocommands change buffers under our fingers, forget about
3608 * re-editing the file. Should do the buf_clear_file(), but perhaps
3609 * the autocommands changed the buffer... */
3610 if (buf != curbuf)
3611 goto theend;
3612# ifdef FEAT_EVAL
3613 if (aborting()) /* autocmds may abort script processing */
3614 goto theend;
3615# endif
3616#endif
3617 buf_clear_file(curbuf);
3618 curbuf->b_op_start.lnum = 0; /* clear '[ and '] marks */
3619 curbuf->b_op_end.lnum = 0;
3620 }
3621
3622/*
3623 * If we get here we are sure to start editing
3624 */
3625 /* don't redraw until the cursor is in the right line */
3626 ++RedrawingDisabled;
3627
3628 /* Assume success now */
3629 retval = OK;
3630
3631 /*
3632 * Reset cursor position, could be used by autocommands.
3633 */
3634 check_cursor();
3635
3636 /*
3637 * Check if we are editing the w_arg_idx file in the argument list.
3638 */
3639 check_arg_idx(curwin);
3640
3641#ifdef FEAT_AUTOCMD
3642 if (!auto_buf)
3643#endif
3644 {
3645 /*
3646 * Set cursor and init window before reading the file and executing
3647 * autocommands. This allows for the autocommands to position the
3648 * cursor.
3649 */
Bram Moolenaarfaa959a2006-02-20 21:37:40 +00003650 curwin_init();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651
3652#ifdef FEAT_FOLDING
Bram Moolenaareb1b6792007-08-21 13:29:28 +00003653 /* It's possible that all lines in the buffer changed. Need to update
3654 * automatic folding for all windows where it's used. */
3655# ifdef FEAT_WINDOWS
3656 {
3657 win_T *win;
3658 tabpage_T *tp;
3659
3660 FOR_ALL_TAB_WINDOWS(tp, win)
3661 if (win->w_buffer == curbuf)
3662 foldUpdateAll(win);
3663 }
3664# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 foldUpdateAll(curwin);
Bram Moolenaareb1b6792007-08-21 13:29:28 +00003666# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667#endif
3668
Bram Moolenaar498efdb2006-09-05 14:31:54 +00003669 /* Change directories when the 'acd' option is set. */
3670 DO_AUTOCHDIR
3671
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 /*
3673 * Careful: open_buffer() and apply_autocmds() may change the current
3674 * buffer and window.
3675 */
3676 lnum = curwin->w_cursor.lnum;
3677 topline = curwin->w_topline;
3678 if (!oldbuf) /* need to read the file */
3679 {
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00003680#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681 swap_exists_action = SEA_DIALOG;
3682#endif
3683 curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */
3684
3685 /*
3686 * Open the buffer and read the file.
3687 */
3688#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
Bram Moolenaar59f931e2010-07-24 20:27:03 +02003689 if (should_abort(open_buffer(FALSE, eap, readfile_flags)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 retval = FAIL;
3691#else
Bram Moolenaar59f931e2010-07-24 20:27:03 +02003692 (void)open_buffer(FALSE, eap, readfile_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693#endif
3694
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00003695#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696 if (swap_exists_action == SEA_QUIT)
3697 retval = FAIL;
3698 handle_swap_exists(old_curbuf);
3699#endif
3700 }
3701#ifdef FEAT_AUTOCMD
3702 else
3703 {
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00003704 /* Read the modelines, but only to set window-local options. Any
3705 * buffer-local options have already been set and may have been
3706 * changed by the user. */
Bram Moolenaara3227e22006-03-08 21:32:40 +00003707 do_modelines(OPT_WINONLY);
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00003708
Bram Moolenaar071d4272004-06-13 20:20:40 +00003709 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf,
3710 &retval);
3711 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
3712 &retval);
3713 }
3714 check_arg_idx(curwin);
3715#endif
3716
3717 /*
3718 * If autocommands change the cursor position or topline, we should
3719 * keep it.
3720 */
3721 if (curwin->w_cursor.lnum != lnum)
3722 {
3723 newlnum = curwin->w_cursor.lnum;
3724 newcol = curwin->w_cursor.col;
3725 }
3726 if (curwin->w_topline == topline)
3727 topline = 0;
3728
3729 /* Even when cursor didn't move we need to recompute topline. */
3730 changed_line_abv_curs();
3731
3732#ifdef FEAT_TITLE
3733 maketitle();
3734#endif
3735 }
3736
3737#ifdef FEAT_DIFF
3738 /* Tell the diff stuff that this buffer is new and/or needs updating.
3739 * Also needed when re-editing the same buffer, because unloading will
3740 * have removed it as a diff buffer. */
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00003741 if (curwin->w_p_diff)
3742 {
3743 diff_buf_add(curbuf);
3744 diff_invalidate(curbuf);
3745 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746#endif
3747
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00003748#ifdef FEAT_SPELL
3749 /* If the window options were changed may need to set the spell language.
3750 * Can only do this after the buffer has been properly setup. */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003751 if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
3752 (void)did_set_spelllang(curwin);
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00003753#endif
3754
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 if (command == NULL)
3756 {
3757 if (newcol >= 0) /* position set by autocommands */
3758 {
3759 curwin->w_cursor.lnum = newlnum;
3760 curwin->w_cursor.col = newcol;
3761 check_cursor();
3762 }
3763 else if (newlnum > 0) /* line number from caller or old position */
3764 {
3765 curwin->w_cursor.lnum = newlnum;
3766 check_cursor_lnum();
3767 if (solcol >= 0 && !p_sol)
3768 {
3769 /* 'sol' is off: Use last known column. */
3770 curwin->w_cursor.col = solcol;
3771 check_cursor_col();
3772#ifdef FEAT_VIRTUALEDIT
3773 curwin->w_cursor.coladd = 0;
3774#endif
3775 curwin->w_set_curswant = TRUE;
3776 }
3777 else
3778 beginline(BL_SOL | BL_FIX);
3779 }
3780 else /* no line number, go to last line in Ex mode */
3781 {
3782 if (exmode_active)
3783 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
3784 beginline(BL_WHITE | BL_FIX);
3785 }
3786 }
3787
3788#ifdef FEAT_WINDOWS
3789 /* Check if cursors in other windows on the same buffer are still valid */
3790 check_lnums(FALSE);
3791#endif
3792
3793 /*
3794 * Did not read the file, need to show some info about the file.
3795 * Do this after setting the cursor.
3796 */
3797 if (oldbuf
3798#ifdef FEAT_AUTOCMD
3799 && !auto_buf
3800#endif
3801 )
3802 {
3803 int msg_scroll_save = msg_scroll;
3804
3805 /* Obey the 'O' flag in 'cpoptions': overwrite any previous file
3806 * message. */
3807 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
3808 msg_scroll = FALSE;
3809 if (!msg_scroll) /* wait a bit when overwriting an error msg */
3810 check_for_delay(FALSE);
3811 msg_start();
3812 msg_scroll = msg_scroll_save;
3813 msg_scrolled_ign = TRUE;
3814
3815 fileinfo(FALSE, TRUE, FALSE);
3816
3817 msg_scrolled_ign = FALSE;
3818 }
3819
3820 if (command != NULL)
3821 do_cmdline(command, NULL, NULL, DOCMD_VERBOSE);
3822
3823#ifdef FEAT_KEYMAP
3824 if (curbuf->b_kmap_state & KEYMAP_INIT)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003825 (void)keymap_init();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826#endif
3827
3828 --RedrawingDisabled;
3829 if (!skip_redraw)
3830 {
3831 n = p_so;
3832 if (topline == 0 && command == NULL)
3833 p_so = 999; /* force cursor halfway the window */
3834 update_topline();
3835#ifdef FEAT_SCROLLBIND
3836 curwin->w_scbind_pos = curwin->w_topline;
3837#endif
3838 p_so = n;
3839 redraw_curbuf_later(NOT_VALID); /* redraw this buffer later */
3840 }
3841
3842 if (p_im)
3843 need_start_insertmode = TRUE;
3844
Bram Moolenaar498efdb2006-09-05 14:31:54 +00003845 /* Change directories when the 'acd' option is set. */
3846 DO_AUTOCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847
Bram Moolenaar7b89edc2006-04-06 20:21:51 +00003848#if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG)
Bram Moolenaar67c53842010-05-22 18:28:27 +02003849 if (curbuf->b_ffname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 {
3851# ifdef FEAT_SUN_WORKSHOP
Bram Moolenaar67c53842010-05-22 18:28:27 +02003852 if (gui.in_use && usingSunWorkShop)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003853 workshop_file_opened((char *)curbuf->b_ffname, curbuf->b_p_ro);
3854# endif
3855# ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003856 if ((flags & ECMD_SET_HELP) != ECMD_SET_HELP)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00003857 netbeans_file_opened(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858# endif
3859 }
3860#endif
3861
3862theend:
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003863#ifdef FEAT_AUTOCMD
3864 if (did_set_swapcommand)
3865 set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
3866#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867#ifdef FEAT_BROWSE
3868 vim_free(browse_file);
3869#endif
3870 vim_free(free_fname);
3871 return retval;
3872}
3873
3874#ifdef FEAT_AUTOCMD
3875 static void
3876delbuf_msg(name)
3877 char_u *name;
3878{
3879 EMSG2(_("E143: Autocommands unexpectedly deleted new buffer %s"),
3880 name == NULL ? (char_u *)"" : name);
3881 vim_free(name);
3882 au_new_curbuf = NULL;
3883}
3884#endif
3885
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003886static int append_indent = 0; /* autoindent for first line */
3887
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888/*
3889 * ":insert" and ":append", also used by ":change"
3890 */
3891 void
3892ex_append(eap)
3893 exarg_T *eap;
3894{
3895 char_u *theline;
3896 int did_undo = FALSE;
3897 linenr_T lnum = eap->line2;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00003898 int indent = 0;
3899 char_u *p;
3900 int vcol;
3901 int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003903 /* the ! flag toggles autoindent */
3904 if (eap->forceit)
3905 curbuf->b_p_ai = !curbuf->b_p_ai;
3906
3907 /* First autoindent comes from the line we start on */
3908 if (eap->cmdidx != CMD_change && curbuf->b_p_ai && lnum > 0)
3909 append_indent = get_indent_lnum(lnum);
3910
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 if (eap->cmdidx != CMD_append)
3912 --lnum;
3913
Bram Moolenaar81bf7082005-02-12 14:31:42 +00003914 /* when the buffer is empty append to line 0 and delete the dummy line */
3915 if (empty && lnum == 1)
3916 lnum = 0;
3917
Bram Moolenaar071d4272004-06-13 20:20:40 +00003918 State = INSERT; /* behave like in Insert mode */
3919 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
3920 State |= LANGMAP;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00003921
Bram Moolenaard8e9bb22005-07-09 21:14:46 +00003922 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923 {
3924 msg_scroll = TRUE;
3925 need_wait_return = FALSE;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003926 if (curbuf->b_p_ai)
3927 {
3928 if (append_indent >= 0)
3929 {
3930 indent = append_indent;
3931 append_indent = -1;
3932 }
3933 else if (lnum > 0)
3934 indent = get_indent_lnum(lnum);
3935 }
3936 ex_keep_indent = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003937 if (eap->getline == NULL)
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003938 {
3939 /* No getline() function, use the lines that follow. This ends
3940 * when there is no more. */
3941 if (eap->nextcmd == NULL || *eap->nextcmd == NUL)
3942 break;
3943 p = vim_strchr(eap->nextcmd, NL);
3944 if (p == NULL)
3945 p = eap->nextcmd + STRLEN(eap->nextcmd);
3946 theline = vim_strnsave(eap->nextcmd, (int)(p - eap->nextcmd));
3947 if (*p != NUL)
3948 ++p;
3949 eap->nextcmd = p;
3950 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951 else
3952 theline = eap->getline(
3953#ifdef FEAT_EVAL
Bram Moolenaar3d60ec22005-01-05 22:19:46 +00003954 eap->cstack->cs_looplevel > 0 ? -1 :
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955#endif
Bram Moolenaar81bf7082005-02-12 14:31:42 +00003956 NUL, eap->cookie, indent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003957 lines_left = Rows - 1;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00003958 if (theline == NULL)
3959 break;
3960
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003961 /* Using ^ CTRL-D in getexmodeline() makes us repeat the indent. */
3962 if (ex_keep_indent)
3963 append_indent = indent;
3964
Bram Moolenaar81bf7082005-02-12 14:31:42 +00003965 /* Look for the "." after automatic indent. */
3966 vcol = 0;
3967 for (p = theline; indent > vcol; ++p)
3968 {
3969 if (*p == ' ')
3970 ++vcol;
3971 else if (*p == TAB)
3972 vcol += 8 - vcol % 8;
3973 else
3974 break;
3975 }
3976 if ((p[0] == '.' && p[1] == NUL)
Bram Moolenaareaa48e72005-06-08 22:07:37 +00003977 || (!did_undo && u_save(lnum, lnum + 1 + (empty ? 1 : 0))
3978 == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979 {
3980 vim_free(theline);
3981 break;
3982 }
3983
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003984 /* don't use autoindent if nothing was typed. */
3985 if (p[0] == NUL)
3986 theline[0] = NUL;
3987
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 did_undo = TRUE;
3989 ml_append(lnum, theline, (colnr_T)0, FALSE);
3990 appended_lines_mark(lnum, 1L);
3991
3992 vim_free(theline);
3993 ++lnum;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00003994
3995 if (empty)
3996 {
3997 ml_delete(2L, FALSE);
3998 empty = FALSE;
3999 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 }
4001 State = NORMAL;
4002
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004003 if (eap->forceit)
4004 curbuf->b_p_ai = !curbuf->b_p_ai;
4005
Bram Moolenaar071d4272004-06-13 20:20:40 +00004006 /* "start" is set to eap->line2+1 unless that position is invalid (when
Bram Moolenaar45667512007-05-10 19:24:43 +00004007 * eap->line2 pointed to the end of the buffer and nothing was appended)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008 * "end" is set to lnum when something has been appended, otherwise
4009 * it is the same than "start" -- Acevedo */
4010 curbuf->b_op_start.lnum = (eap->line2 < curbuf->b_ml.ml_line_count) ?
4011 eap->line2 + 1 : curbuf->b_ml.ml_line_count;
4012 if (eap->cmdidx != CMD_append)
4013 --curbuf->b_op_start.lnum;
4014 curbuf->b_op_end.lnum = (eap->line2 < lnum)
4015 ? lnum : curbuf->b_op_start.lnum;
4016 curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
4017 curwin->w_cursor.lnum = lnum;
4018 check_cursor_lnum();
4019 beginline(BL_SOL | BL_FIX);
4020
4021 need_wait_return = FALSE; /* don't use wait_return() now */
4022 ex_no_reprint = TRUE;
4023}
4024
4025/*
4026 * ":change"
4027 */
4028 void
4029ex_change(eap)
4030 exarg_T *eap;
4031{
4032 linenr_T lnum;
4033
4034 if (eap->line2 >= eap->line1
4035 && u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
4036 return;
4037
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004038 /* the ! flag toggles autoindent */
4039 if (eap->forceit ? !curbuf->b_p_ai : curbuf->b_p_ai)
4040 append_indent = get_indent_lnum(eap->line1);
4041
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 for (lnum = eap->line2; lnum >= eap->line1; --lnum)
4043 {
4044 if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
4045 break;
4046 ml_delete(eap->line1, FALSE);
4047 }
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00004048
4049 /* make sure the cursor is not beyond the end of the file now */
4050 check_cursor_lnum();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051 deleted_lines_mark(eap->line1, (long)(eap->line2 - lnum));
4052
4053 /* ":append" on the line above the deleted lines. */
4054 eap->line2 = eap->line1;
4055 ex_append(eap);
4056}
4057
4058 void
4059ex_z(eap)
4060 exarg_T *eap;
4061{
4062 char_u *x;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004063 int bigness;
4064 char_u *kind;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065 int minus = 0;
4066 linenr_T start, end, curs, i;
4067 int j;
4068 linenr_T lnum = eap->line2;
4069
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004070 /* Vi compatible: ":z!" uses display height, without a count uses
4071 * 'scroll' */
4072 if (eap->forceit)
4073 bigness = curwin->w_height;
4074 else if (firstwin == lastwin)
4075 bigness = curwin->w_p_scr * 2;
Bram Moolenaar78a15312009-05-15 19:33:18 +00004076#ifdef FEAT_WINDOWS
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004077 else
4078 bigness = curwin->w_height - 3;
Bram Moolenaar78a15312009-05-15 19:33:18 +00004079#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080 if (bigness < 1)
4081 bigness = 1;
4082
4083 x = eap->arg;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004084 kind = x;
4085 if (*kind == '-' || *kind == '+' || *kind == '='
4086 || *kind == '^' || *kind == '.')
4087 ++x;
4088 while (*x == '-' || *x == '+')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004089 ++x;
4090
4091 if (*x != 0)
4092 {
4093 if (!VIM_ISDIGIT(*x))
4094 {
4095 EMSG(_("E144: non-numeric argument to :z"));
4096 return;
4097 }
4098 else
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004099 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100 bigness = atoi((char *)x);
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004101 p_window = bigness;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004102 if (*kind == '=')
4103 bigness += 2;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004104 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105 }
4106
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004107 /* the number of '-' and '+' multiplies the distance */
4108 if (*kind == '-' || *kind == '+')
4109 for (x = kind + 1; *x == *kind; ++x)
4110 ;
4111
4112 switch (*kind)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113 {
4114 case '-':
Bram Moolenaard9758e32011-06-12 22:03:23 +02004115 start = lnum - bigness * (linenr_T)(x - kind) + 1;
4116 end = start + bigness - 1;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004117 curs = end;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 break;
4119
4120 case '=':
Bram Moolenaar2a8d1f82005-02-05 21:43:56 +00004121 start = lnum - (bigness + 1) / 2 + 1;
4122 end = lnum + (bigness + 1) / 2 - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123 curs = lnum;
4124 minus = 1;
4125 break;
4126
4127 case '^':
4128 start = lnum - bigness * 2;
4129 end = lnum - bigness;
4130 curs = lnum - bigness;
4131 break;
4132
4133 case '.':
Bram Moolenaar2a8d1f82005-02-05 21:43:56 +00004134 start = lnum - (bigness + 1) / 2 + 1;
4135 end = lnum + (bigness + 1) / 2 - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136 curs = end;
4137 break;
4138
4139 default: /* '+' */
4140 start = lnum;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004141 if (*kind == '+')
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004142 start += bigness * (linenr_T)(x - kind - 1) + 1;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004143 else if (eap->addr_count == 0)
4144 ++start;
4145 end = start + bigness - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 curs = end;
4147 break;
4148 }
4149
4150 if (start < 1)
4151 start = 1;
4152
4153 if (end > curbuf->b_ml.ml_line_count)
4154 end = curbuf->b_ml.ml_line_count;
4155
4156 if (curs > curbuf->b_ml.ml_line_count)
4157 curs = curbuf->b_ml.ml_line_count;
4158
4159 for (i = start; i <= end; i++)
4160 {
4161 if (minus && i == lnum)
4162 {
4163 msg_putchar('\n');
4164
4165 for (j = 1; j < Columns; j++)
4166 msg_putchar('-');
4167 }
4168
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004169 print_line(i, eap->flags & EXFLAG_NR, eap->flags & EXFLAG_LIST);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004170
4171 if (minus && i == lnum)
4172 {
4173 msg_putchar('\n');
4174
4175 for (j = 1; j < Columns; j++)
4176 msg_putchar('-');
4177 }
4178 }
4179
4180 curwin->w_cursor.lnum = curs;
4181 ex_no_reprint = TRUE;
4182}
4183
4184/*
4185 * Check if the restricted flag is set.
4186 * If so, give an error message and return TRUE.
4187 * Otherwise, return FALSE.
4188 */
4189 int
4190check_restricted()
4191{
4192 if (restricted)
4193 {
4194 EMSG(_("E145: Shell commands not allowed in rvim"));
4195 return TRUE;
4196 }
4197 return FALSE;
4198}
4199
4200/*
4201 * Check if the secure flag is set (.exrc or .vimrc in current directory).
4202 * If so, give an error message and return TRUE.
4203 * Otherwise, return FALSE.
4204 */
4205 int
4206check_secure()
4207{
4208 if (secure)
4209 {
4210 secure = 2;
4211 EMSG(_(e_curdir));
4212 return TRUE;
4213 }
4214#ifdef HAVE_SANDBOX
4215 /*
4216 * In the sandbox more things are not allowed, including the things
4217 * disallowed in secure mode.
4218 */
4219 if (sandbox != 0)
4220 {
4221 EMSG(_(e_sandbox));
4222 return TRUE;
4223 }
4224#endif
4225 return FALSE;
4226}
4227
4228static char_u *old_sub = NULL; /* previous substitute pattern */
4229static int global_need_beginline; /* call beginline() after ":g" */
4230
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231/* do_sub()
4232 *
4233 * Perform a substitution from line eap->line1 to line eap->line2 using the
4234 * command pointed to by eap->arg which should be of the form:
4235 *
4236 * /pattern/substitution/{flags}
4237 *
4238 * The usual escapes are supported as described in the regexp docs.
4239 */
4240 void
4241do_sub(eap)
4242 exarg_T *eap;
4243{
4244 linenr_T lnum;
4245 long i = 0;
4246 regmmatch_T regmatch;
4247 static int do_all = FALSE; /* do multiple substitutions per line */
4248 static int do_ask = FALSE; /* ask for confirmation */
Bram Moolenaar05159a02005-02-26 23:04:13 +00004249 static int do_count = FALSE; /* count only */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 static int do_error = TRUE; /* if false, ignore errors */
4251 static int do_print = FALSE; /* print last line with subs. */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004252 static int do_list = FALSE; /* list last line with subs. */
4253 static int do_number = FALSE; /* list last line with line nr*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 static int do_ic = 0; /* ignore case flag */
4255 char_u *pat = NULL, *sub = NULL; /* init for GCC */
4256 int delimiter;
4257 int sublen;
4258 int got_quit = FALSE;
4259 int got_match = FALSE;
4260 int temp;
4261 int which_pat;
4262 char_u *cmd;
4263 int save_State;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004264 linenr_T first_line = 0; /* first changed line */
4265 linenr_T last_line= 0; /* below last changed line AFTER the
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266 * change */
4267 linenr_T old_line_count = curbuf->b_ml.ml_line_count;
4268 linenr_T line2;
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004269 long nmatch; /* number of lines in match */
Bram Moolenaar81bf7082005-02-12 14:31:42 +00004270 char_u *sub_firstline; /* allocated copy of first sub line */
4271 int endcolumn = FALSE; /* cursor in last column when done */
Bram Moolenaar05159a02005-02-26 23:04:13 +00004272 pos_T old_cursor = curwin->w_cursor;
Bram Moolenaar46475522010-03-23 17:36:29 +01004273 int start_nsubs;
Bram Moolenaar07e31c52012-08-08 16:51:15 +02004274#ifdef FEAT_EVAL
4275 int save_ma = 0;
4276#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277
4278 cmd = eap->arg;
4279 if (!global_busy)
4280 {
4281 sub_nsubs = 0;
4282 sub_nlines = 0;
4283 }
Bram Moolenaar46475522010-03-23 17:36:29 +01004284 start_nsubs = sub_nsubs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286 if (eap->cmdidx == CMD_tilde)
4287 which_pat = RE_LAST; /* use last used regexp */
4288 else
4289 which_pat = RE_SUBST; /* use last substitute regexp */
4290
4291 /* new pattern and substitution */
4292 if (eap->cmd[0] == 's' && *cmd != NUL && !vim_iswhite(*cmd)
4293 && vim_strchr((char_u *)"0123456789cegriIp|\"", *cmd) == NULL)
4294 {
4295 /* don't accept alphanumeric for separator */
4296 if (isalpha(*cmd))
4297 {
4298 EMSG(_("E146: Regular expressions can't be delimited by letters"));
4299 return;
4300 }
4301 /*
4302 * undocumented vi feature:
4303 * "\/sub/" and "\?sub?" use last used search pattern (almost like
4304 * //sub/r). "\&sub&" use last substitute pattern (like //sub/).
4305 */
4306 if (*cmd == '\\')
4307 {
4308 ++cmd;
4309 if (vim_strchr((char_u *)"/?&", *cmd) == NULL)
4310 {
4311 EMSG(_(e_backslash));
4312 return;
4313 }
4314 if (*cmd != '&')
4315 which_pat = RE_SEARCH; /* use last '/' pattern */
4316 pat = (char_u *)""; /* empty search pattern */
4317 delimiter = *cmd++; /* remember delimiter character */
4318 }
4319 else /* find the end of the regexp */
4320 {
Bram Moolenaar3a169c32008-01-02 12:59:21 +00004321#ifdef FEAT_FKMAP /* reverse the flow of the Farsi characters */
4322 if (p_altkeymap && curwin->w_p_rl)
4323 lrF_sub(cmd);
4324#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325 which_pat = RE_LAST; /* use last used regexp */
4326 delimiter = *cmd++; /* remember delimiter character */
4327 pat = cmd; /* remember start of search pat */
4328 cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg);
4329 if (cmd[0] == delimiter) /* end delimiter found */
4330 *cmd++ = NUL; /* replace it with a NUL */
4331 }
4332
4333 /*
4334 * Small incompatibility: vi sees '\n' as end of the command, but in
4335 * Vim we want to use '\n' to find/substitute a NUL.
4336 */
4337 sub = cmd; /* remember the start of the substitution */
4338
4339 while (cmd[0])
4340 {
4341 if (cmd[0] == delimiter) /* end delimiter found */
4342 {
4343 *cmd++ = NUL; /* replace it with a NUL */
4344 break;
4345 }
4346 if (cmd[0] == '\\' && cmd[1] != 0) /* skip escaped characters */
4347 ++cmd;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004348 mb_ptr_adv(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 }
4350
4351 if (!eap->skip)
4352 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004353 /* In POSIX vi ":s/pat/%/" uses the previous subst. string. */
4354 if (STRCMP(sub, "%") == 0
4355 && vim_strchr(p_cpo, CPO_SUBPERCENT) != NULL)
4356 {
4357 if (old_sub == NULL) /* there is no previous command */
4358 {
4359 EMSG(_(e_nopresub));
4360 return;
4361 }
4362 sub = old_sub;
4363 }
4364 else
4365 {
4366 vim_free(old_sub);
4367 old_sub = vim_strsave(sub);
4368 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 }
4370 }
4371 else if (!eap->skip) /* use previous pattern and substitution */
4372 {
4373 if (old_sub == NULL) /* there is no previous command */
4374 {
4375 EMSG(_(e_nopresub));
4376 return;
4377 }
4378 pat = NULL; /* search_regcomp() will use previous pattern */
4379 sub = old_sub;
Bram Moolenaarb11bd7e2005-02-07 22:05:52 +00004380
4381 /* Vi compatibility quirk: repeating with ":s" keeps the cursor in the
4382 * last column after using "$". */
4383 endcolumn = (curwin->w_curswant == MAXCOL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 }
4385
4386 /*
4387 * Find trailing options. When '&' is used, keep old options.
4388 */
4389 if (*cmd == '&')
4390 ++cmd;
4391 else
4392 {
4393 if (!p_ed)
4394 {
4395 if (p_gd) /* default is global on */
4396 do_all = TRUE;
4397 else
4398 do_all = FALSE;
4399 do_ask = FALSE;
4400 }
4401 do_error = TRUE;
4402 do_print = FALSE;
Bram Moolenaarcc016f52005-12-10 20:23:46 +00004403 do_count = FALSE;
Bram Moolenaarfe40d1a2007-07-24 09:16:38 +00004404 do_number = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405 do_ic = 0;
4406 }
4407 while (*cmd)
4408 {
4409 /*
4410 * Note that 'g' and 'c' are always inverted, also when p_ed is off.
4411 * 'r' is never inverted.
4412 */
4413 if (*cmd == 'g')
4414 do_all = !do_all;
4415 else if (*cmd == 'c')
4416 do_ask = !do_ask;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004417 else if (*cmd == 'n')
4418 do_count = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004419 else if (*cmd == 'e')
4420 do_error = !do_error;
4421 else if (*cmd == 'r') /* use last used regexp */
4422 which_pat = RE_LAST;
4423 else if (*cmd == 'p')
4424 do_print = TRUE;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004425 else if (*cmd == '#')
4426 {
4427 do_print = TRUE;
4428 do_number = TRUE;
4429 }
4430 else if (*cmd == 'l')
4431 {
4432 do_print = TRUE;
4433 do_list = TRUE;
4434 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435 else if (*cmd == 'i') /* ignore case */
4436 do_ic = 'i';
4437 else if (*cmd == 'I') /* don't ignore case */
4438 do_ic = 'I';
4439 else
4440 break;
4441 ++cmd;
4442 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004443 if (do_count)
4444 do_ask = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445
4446 /*
4447 * check for a trailing count
4448 */
4449 cmd = skipwhite(cmd);
4450 if (VIM_ISDIGIT(*cmd))
4451 {
4452 i = getdigits(&cmd);
4453 if (i <= 0 && !eap->skip && do_error)
4454 {
4455 EMSG(_(e_zerocount));
4456 return;
4457 }
4458 eap->line1 = eap->line2;
4459 eap->line2 += i - 1;
4460 if (eap->line2 > curbuf->b_ml.ml_line_count)
4461 eap->line2 = curbuf->b_ml.ml_line_count;
4462 }
4463
4464 /*
4465 * check for trailing command or garbage
4466 */
4467 cmd = skipwhite(cmd);
4468 if (*cmd && *cmd != '"') /* if not end-of-line or comment */
4469 {
4470 eap->nextcmd = check_nextcmd(cmd);
4471 if (eap->nextcmd == NULL)
4472 {
4473 EMSG(_(e_trailing));
4474 return;
4475 }
4476 }
4477
4478 if (eap->skip) /* not executing commands, only parsing */
4479 return;
4480
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004481 if (!do_count && !curbuf->b_p_ma)
4482 {
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004483 /* Substitution is not allowed in non-'modifiable' buffer */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004484 EMSG(_(e_modifiable));
4485 return;
4486 }
4487
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 if (search_regcomp(pat, RE_SUBST, which_pat, SEARCH_HIS, &regmatch) == FAIL)
4489 {
4490 if (do_error)
4491 EMSG(_(e_invcmd));
4492 return;
4493 }
4494
4495 /* the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' */
4496 if (do_ic == 'i')
4497 regmatch.rmm_ic = TRUE;
4498 else if (do_ic == 'I')
4499 regmatch.rmm_ic = FALSE;
4500
4501 sub_firstline = NULL;
4502
4503 /*
4504 * ~ in the substitute pattern is replaced with the old pattern.
4505 * We do it here once to avoid it to be replaced over and over again.
4506 * But don't do it when it starts with "\=", then it's an expression.
4507 */
4508 if (!(sub[0] == '\\' && sub[1] == '='))
4509 sub = regtilde(sub, p_magic);
4510
4511 /*
4512 * Check for a match on each line.
4513 */
4514 line2 = eap->line2;
4515 for (lnum = eap->line1; lnum <= line2 && !(got_quit
4516#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
4517 || aborting()
4518#endif
4519 ); ++lnum)
4520 {
Bram Moolenaar91a4e822008-01-19 14:59:58 +00004521 nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
4522 (colnr_T)0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523 if (nmatch)
4524 {
4525 colnr_T copycol;
4526 colnr_T matchcol;
4527 colnr_T prev_matchcol = MAXCOL;
4528 char_u *new_end, *new_start = NULL;
4529 unsigned new_start_len = 0;
4530 char_u *p1;
4531 int did_sub = FALSE;
4532 int lastone;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004533 int len, copy_len, needed_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 long nmatch_tl = 0; /* nr of lines matched below lnum */
4535 int do_again; /* do it again after joining lines */
Bram Moolenaar8299df92004-07-10 09:47:34 +00004536 int skip_match = FALSE;
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00004537 linenr_T sub_firstlnum; /* nr of first sub line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538
4539 /*
4540 * The new text is build up step by step, to avoid too much
4541 * copying. There are these pieces:
Bram Moolenaara9aafe52008-05-07 11:10:28 +00004542 * sub_firstline The old text, unmodified.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 * copycol Column in the old text where we started
4544 * looking for a match; from here old text still
4545 * needs to be copied to the new text.
4546 * matchcol Column number of the old text where to look
4547 * for the next match. It's just after the
4548 * previous match or one further.
4549 * prev_matchcol Column just after the previous match (if any).
4550 * Mostly equal to matchcol, except for the first
4551 * match and after skipping an empty match.
4552 * regmatch.*pos Where the pattern matched in the old text.
4553 * new_start The new text, all that has been produced so
4554 * far.
4555 * new_end The new text, where to append new text.
4556 *
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00004557 * lnum The line number where we found the start of
4558 * the match. Can be below the line we searched
4559 * when there is a \n before a \zs in the
4560 * pattern.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561 * sub_firstlnum The line number in the buffer where to look
4562 * for a match. Can be different from "lnum"
4563 * when the pattern or substitute string contains
4564 * line breaks.
4565 *
4566 * Special situations:
4567 * - When the substitute string contains a line break, the part up
4568 * to the line break is inserted in the text, but the copy of
4569 * the original line is kept. "sub_firstlnum" is adjusted for
4570 * the inserted lines.
4571 * - When the matched pattern contains a line break, the old line
4572 * is taken from the line at the end of the pattern. The lines
4573 * in the match are deleted later, "sub_firstlnum" is adjusted
4574 * accordingly.
4575 *
4576 * The new text is built up in new_start[]. It has some extra
4577 * room to avoid using alloc()/free() too often. new_start_len is
Bram Moolenaar61abfd12007-09-13 16:26:47 +00004578 * the length of the allocated memory at new_start.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579 *
4580 * Make a copy of the old line, so it won't be taken away when
4581 * updating the screen or handling a multi-line match. The "old_"
4582 * pointers point into this copy.
4583 */
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00004584 sub_firstlnum = lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585 copycol = 0;
4586 matchcol = 0;
4587
4588 /* At first match, remember current cursor position. */
4589 if (!got_match)
4590 {
4591 setpcmark();
4592 got_match = TRUE;
4593 }
4594
4595 /*
4596 * Loop until nothing more to replace in this line.
4597 * 1. Handle match with empty string.
4598 * 2. If do_ask is set, ask for confirmation.
4599 * 3. substitute the string.
4600 * 4. if do_all is set, find next match
4601 * 5. break if there isn't another match in this line
4602 */
4603 for (;;)
4604 {
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00004605 /* Advance "lnum" to the line where the match starts. The
4606 * match does not start in the first line when there is a line
4607 * break before \zs. */
4608 if (regmatch.startpos[0].lnum > 0)
4609 {
4610 lnum += regmatch.startpos[0].lnum;
4611 sub_firstlnum += regmatch.startpos[0].lnum;
4612 nmatch -= regmatch.startpos[0].lnum;
4613 vim_free(sub_firstline);
4614 sub_firstline = NULL;
4615 }
4616
4617 if (sub_firstline == NULL)
4618 {
4619 sub_firstline = vim_strsave(ml_get(sub_firstlnum));
4620 if (sub_firstline == NULL)
4621 {
4622 vim_free(new_start);
4623 goto outofmem;
4624 }
4625 }
4626
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 /* Save the line number of the last change for the final
4628 * cursor position (just like Vi). */
4629 curwin->w_cursor.lnum = lnum;
4630 do_again = FALSE;
4631
4632 /*
4633 * 1. Match empty string does not count, except for first
4634 * match. This reproduces the strange vi behaviour.
4635 * This also catches endless loops.
4636 */
4637 if (matchcol == prev_matchcol
4638 && regmatch.endpos[0].lnum == 0
4639 && matchcol == regmatch.endpos[0].col)
4640 {
Bram Moolenaar8299df92004-07-10 09:47:34 +00004641 if (sub_firstline[matchcol] == NUL)
4642 /* We already were at the end of the line. Don't look
4643 * for a match in this line again. */
4644 skip_match = TRUE;
4645 else
Bram Moolenaar0df11022011-05-19 14:30:16 +02004646 {
4647 /* search for a match at next column */
4648#ifdef FEAT_MBYTE
4649 if (has_mbyte)
4650 matchcol += mb_ptr2len(sub_firstline + matchcol);
4651 else
4652#endif
4653 ++matchcol;
4654 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655 goto skip;
4656 }
4657
4658 /* Normally we continue searching for a match just after the
4659 * previous match. */
4660 matchcol = regmatch.endpos[0].col;
4661 prev_matchcol = matchcol;
4662
4663 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +00004664 * 2. If do_count is set only increase the counter.
4665 * If do_ask is set, ask for confirmation.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004666 */
Bram Moolenaar05159a02005-02-26 23:04:13 +00004667 if (do_count)
4668 {
4669 /* For a multi-line match, put matchcol at the NUL at
4670 * the end of the line and set nmatch to one, so that
4671 * we continue looking for a match on the next line.
4672 * Avoids that ":s/\nB\@=//gc" get stuck. */
4673 if (nmatch > 1)
4674 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004675 matchcol = (colnr_T)STRLEN(sub_firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004676 nmatch = 1;
Bram Moolenaar12ddc3e2008-01-04 13:53:09 +00004677 skip_match = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004678 }
4679 sub_nsubs++;
4680 did_sub = TRUE;
Bram Moolenaar07e31c52012-08-08 16:51:15 +02004681#ifdef FEAT_EVAL
4682 /* Skip the substitution, unless an expression is used,
4683 * then it is evaluated in the sandbox. */
4684 if (!(sub[0] == '\\' && sub[1] == '='))
4685#endif
4686 goto skip;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004687 }
4688
Bram Moolenaar071d4272004-06-13 20:20:40 +00004689 if (do_ask)
4690 {
Bram Moolenaar985cb442009-05-14 19:51:46 +00004691 int typed = 0;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004692
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693 /* change State to CONFIRM, so that the mouse works
4694 * properly */
4695 save_State = State;
4696 State = CONFIRM;
4697#ifdef FEAT_MOUSE
4698 setmouse(); /* disable mouse in xterm */
4699#endif
4700 curwin->w_cursor.col = regmatch.startpos[0].col;
4701
4702 /* When 'cpoptions' contains "u" don't sync undo when
4703 * asking for confirmation. */
4704 if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
4705 ++no_u_sync;
4706
4707 /*
4708 * Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
4709 */
4710 while (do_ask)
4711 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004712 if (exmode_active)
4713 {
4714 char_u *resp;
4715 colnr_T sc, ec;
4716
4717 print_line_no_prefix(lnum, FALSE, FALSE);
4718
4719 getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL);
4720 curwin->w_cursor.col = regmatch.endpos[0].col - 1;
4721 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
4722 msg_start();
Bram Moolenaar05159a02005-02-26 23:04:13 +00004723 for (i = 0; i < (long)sc; ++i)
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004724 msg_putchar(' ');
Bram Moolenaar05159a02005-02-26 23:04:13 +00004725 for ( ; i <= (long)ec; ++i)
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004726 msg_putchar('^');
4727
4728 resp = getexmodeline('?', NULL, 0);
4729 if (resp != NULL)
4730 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004731 typed = *resp;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004732 vim_free(resp);
4733 }
4734 }
4735 else
4736 {
Bram Moolenaar4bc8cf02013-01-30 16:30:26 +01004737 char_u *orig_line = NULL;
4738 int len_change = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739#ifdef FEAT_FOLDING
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004740 int save_p_fen = curwin->w_p_fen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004742 curwin->w_p_fen = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743#endif
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004744 /* Invert the matched string.
4745 * Remove the inversion afterwards. */
4746 temp = RedrawingDisabled;
4747 RedrawingDisabled = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748
Bram Moolenaar4bc8cf02013-01-30 16:30:26 +01004749 if (new_start != NULL)
4750 {
4751 /* There already was a substitution, we would
4752 * like to show this to the user. We cannot
4753 * really update the line, it would change
4754 * what matches. Temporarily replace the line
4755 * and change it back afterwards. */
4756 orig_line = vim_strsave(ml_get(lnum));
4757 if (orig_line != NULL)
4758 {
4759 char_u *new_line = concat_str(new_start,
4760 sub_firstline + copycol);
4761
4762 if (new_line == NULL)
4763 {
4764 vim_free(orig_line);
4765 orig_line = NULL;
4766 }
4767 else
4768 {
4769 /* Position the cursor relative to the
4770 * end of the line, the previous
4771 * substitute may have inserted or
4772 * deleted characters before the
4773 * cursor. */
Bram Moolenaar04e5b5a2013-01-30 21:56:21 +01004774 len_change = (int)STRLEN(new_line)
4775 - (int)STRLEN(orig_line);
Bram Moolenaar4bc8cf02013-01-30 16:30:26 +01004776 curwin->w_cursor.col += len_change;
4777 ml_replace(lnum, new_line, FALSE);
4778 }
4779 }
4780 }
4781
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00004782 search_match_lines = regmatch.endpos[0].lnum
4783 - regmatch.startpos[0].lnum;
Bram Moolenaar4bc8cf02013-01-30 16:30:26 +01004784 search_match_endcol = regmatch.endpos[0].col
4785 + len_change;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004786 highlight_match = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004788 update_topline();
4789 validate_cursor();
Bram Moolenaara1956f62006-03-12 22:18:00 +00004790 update_screen(SOME_VALID);
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004791 highlight_match = FALSE;
Bram Moolenaara1956f62006-03-12 22:18:00 +00004792 redraw_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004793
4794#ifdef FEAT_FOLDING
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004795 curwin->w_p_fen = save_p_fen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796#endif
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004797 if (msg_row == Rows - 1)
4798 msg_didout = FALSE; /* avoid a scroll-up */
4799 msg_starthere();
4800 i = msg_scroll;
4801 msg_scroll = 0; /* truncate msg when
4802 needed */
4803 msg_no_more = TRUE;
4804 /* write message same highlighting as for
4805 * wait_return */
4806 smsg_attr(hl_attr(HLF_R),
4807 (char_u *)_("replace with %s (y/n/a/q/l/^E/^Y)?"), sub);
4808 msg_no_more = FALSE;
4809 msg_scroll = i;
4810 showruler(TRUE);
4811 windgoto(msg_row, msg_col);
4812 RedrawingDisabled = temp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813
4814#ifdef USE_ON_FLY_SCROLL
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004815 dont_scroll = FALSE; /* allow scrolling here */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004816#endif
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004817 ++no_mapping; /* don't map this key */
4818 ++allow_keys; /* allow special keys */
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004819 typed = plain_vgetc();
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004820 --allow_keys;
4821 --no_mapping;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004823 /* clear the question */
4824 msg_didout = FALSE; /* don't scroll up */
4825 msg_col = 0;
4826 gotocmdline(TRUE);
Bram Moolenaar4bc8cf02013-01-30 16:30:26 +01004827
4828 /* restore the line */
4829 if (orig_line != NULL)
4830 ml_replace(lnum, orig_line, FALSE);
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004831 }
4832
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833 need_wait_return = FALSE; /* no hit-return prompt */
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004834 if (typed == 'q' || typed == ESC || typed == Ctrl_C
Bram Moolenaar071d4272004-06-13 20:20:40 +00004835#ifdef UNIX
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004836 || typed == intr_char
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837#endif
4838 )
4839 {
4840 got_quit = TRUE;
4841 break;
4842 }
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004843 if (typed == 'n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004844 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004845 if (typed == 'y')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846 break;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004847 if (typed == 'l')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848 {
4849 /* last: replace and then stop */
4850 do_all = FALSE;
4851 line2 = lnum;
4852 break;
4853 }
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004854 if (typed == 'a')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004855 {
4856 do_ask = FALSE;
4857 break;
4858 }
4859#ifdef FEAT_INS_EXPAND
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004860 if (typed == Ctrl_E)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004861 scrollup_clamp();
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004862 else if (typed == Ctrl_Y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863 scrolldown_clamp();
4864#endif
4865 }
4866 State = save_State;
4867#ifdef FEAT_MOUSE
4868 setmouse();
4869#endif
4870 if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
4871 --no_u_sync;
4872
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004873 if (typed == 'n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 {
4875 /* For a multi-line match, put matchcol at the NUL at
4876 * the end of the line and set nmatch to one, so that
4877 * we continue looking for a match on the next line.
Bram Moolenaarc432b502007-03-15 20:38:26 +00004878 * Avoids that ":%s/\nB\@=//gc" and ":%s/\n/,\r/gc"
4879 * get stuck when pressing 'n'. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004880 if (nmatch > 1)
4881 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004882 matchcol = (colnr_T)STRLEN(sub_firstline);
Bram Moolenaarc432b502007-03-15 20:38:26 +00004883 skip_match = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 }
4885 goto skip;
4886 }
4887 if (got_quit)
Bram Moolenaar11cb6e62013-02-06 18:24:02 +01004888 goto skip;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889 }
4890
4891 /* Move the cursor to the start of the match, so that we can
4892 * use "\=col("."). */
4893 curwin->w_cursor.col = regmatch.startpos[0].col;
4894
4895 /*
4896 * 3. substitute the string.
4897 */
Bram Moolenaar07e31c52012-08-08 16:51:15 +02004898#ifdef FEAT_EVAL
4899 if (do_count)
4900 {
Bram Moolenaar7c0a86b2012-09-05 15:15:07 +02004901 /* prevent accidentally changing the buffer by a function */
Bram Moolenaar07e31c52012-08-08 16:51:15 +02004902 save_ma = curbuf->b_p_ma;
4903 curbuf->b_p_ma = FALSE;
4904 sandbox++;
4905 }
4906#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 /* get length of substitution part */
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00004908 sublen = vim_regsub_multi(&regmatch,
4909 sub_firstlnum - regmatch.startpos[0].lnum,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910 sub, sub_firstline, FALSE, p_magic, TRUE);
Bram Moolenaar07e31c52012-08-08 16:51:15 +02004911#ifdef FEAT_EVAL
4912 if (do_count)
4913 {
4914 curbuf->b_p_ma = save_ma;
4915 sandbox--;
4916 goto skip;
4917 }
4918#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004919
Bram Moolenaar4463f292005-09-25 22:20:24 +00004920 /* When the match included the "$" of the last line it may
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004921 * go beyond the last line of the buffer. */
Bram Moolenaar4463f292005-09-25 22:20:24 +00004922 if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1)
4923 {
4924 nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
4925 skip_match = TRUE;
4926 }
4927
Bram Moolenaar071d4272004-06-13 20:20:40 +00004928 /* Need room for:
4929 * - result so far in new_start (not for first sub in line)
4930 * - original text up to match
4931 * - length of substituted part
4932 * - original text after match
4933 */
4934 if (nmatch == 1)
4935 p1 = sub_firstline;
4936 else
4937 {
4938 p1 = ml_get(sub_firstlnum + nmatch - 1);
4939 nmatch_tl += nmatch - 1;
4940 }
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004941 copy_len = regmatch.startpos[0].col - copycol;
4942 needed_len = copy_len + ((unsigned)STRLEN(p1)
4943 - regmatch.endpos[0].col) + sublen + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004944 if (new_start == NULL)
4945 {
4946 /*
4947 * Get some space for a temporary buffer to do the
4948 * substitution into (and some extra space to avoid
4949 * too many calls to alloc()/free()).
4950 */
4951 new_start_len = needed_len + 50;
4952 if ((new_start = alloc_check(new_start_len)) == NULL)
4953 goto outofmem;
4954 *new_start = NUL;
4955 new_end = new_start;
4956 }
4957 else
4958 {
4959 /*
4960 * Check if the temporary buffer is long enough to do the
4961 * substitution into. If not, make it larger (with a bit
4962 * extra to avoid too many calls to alloc()/free()).
4963 */
4964 len = (unsigned)STRLEN(new_start);
4965 needed_len += len;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004966 if (needed_len > (int)new_start_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967 {
4968 new_start_len = needed_len + 50;
4969 if ((p1 = alloc_check(new_start_len)) == NULL)
4970 {
4971 vim_free(new_start);
4972 goto outofmem;
4973 }
4974 mch_memmove(p1, new_start, (size_t)(len + 1));
4975 vim_free(new_start);
4976 new_start = p1;
4977 }
4978 new_end = new_start + len;
4979 }
4980
4981 /*
4982 * copy the text up to the part that matched
4983 */
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004984 mch_memmove(new_end, sub_firstline + copycol, (size_t)copy_len);
4985 new_end += copy_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004986
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00004987 (void)vim_regsub_multi(&regmatch,
4988 sub_firstlnum - regmatch.startpos[0].lnum,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989 sub, new_end, TRUE, p_magic, TRUE);
4990 sub_nsubs++;
4991 did_sub = TRUE;
4992
4993 /* Move the cursor to the start of the line, to avoid that it
4994 * is beyond the end of the line after the substitution. */
4995 curwin->w_cursor.col = 0;
4996
4997 /* For a multi-line match, make a copy of the last matched
4998 * line and continue in that one. */
4999 if (nmatch > 1)
5000 {
5001 sub_firstlnum += nmatch - 1;
5002 vim_free(sub_firstline);
5003 sub_firstline = vim_strsave(ml_get(sub_firstlnum));
5004 /* When going beyond the last line, stop substituting. */
5005 if (sub_firstlnum <= line2)
5006 do_again = TRUE;
5007 else
5008 do_all = FALSE;
5009 }
5010
5011 /* Remember next character to be copied. */
5012 copycol = regmatch.endpos[0].col;
5013
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005014 if (skip_match)
5015 {
5016 /* Already hit end of the buffer, sub_firstlnum is one
5017 * less than what it ought to be. */
5018 vim_free(sub_firstline);
5019 sub_firstline = vim_strsave((char_u *)"");
5020 copycol = 0;
5021 }
5022
Bram Moolenaar071d4272004-06-13 20:20:40 +00005023 /*
5024 * Now the trick is to replace CTRL-M chars with a real line
5025 * break. This would make it impossible to insert a CTRL-M in
5026 * the text. The line break can be avoided by preceding the
5027 * CTRL-M with a backslash. To be able to insert a backslash,
5028 * they must be doubled in the string and are halved here.
5029 * That is Vi compatible.
5030 */
5031 for (p1 = new_end; *p1; ++p1)
5032 {
5033 if (p1[0] == '\\' && p1[1] != NUL) /* remove backslash */
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005034 STRMOVE(p1, p1 + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005035 else if (*p1 == CAR)
5036 {
5037 if (u_inssub(lnum) == OK) /* prepare for undo */
5038 {
5039 *p1 = NUL; /* truncate up to the CR */
5040 ml_append(lnum - 1, new_start,
5041 (colnr_T)(p1 - new_start + 1), FALSE);
5042 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
5043 if (do_ask)
5044 appended_lines(lnum - 1, 1L);
5045 else
5046 {
5047 if (first_line == 0)
5048 first_line = lnum;
5049 last_line = lnum + 1;
5050 }
5051 /* All line numbers increase. */
5052 ++sub_firstlnum;
5053 ++lnum;
5054 ++line2;
5055 /* move the cursor to the new line, like Vi */
5056 ++curwin->w_cursor.lnum;
Bram Moolenaarf9ffd182007-11-20 17:04:29 +00005057 /* copy the rest */
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005058 STRMOVE(new_start, p1 + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005059 p1 = new_start - 1;
5060 }
5061 }
5062#ifdef FEAT_MBYTE
5063 else if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005064 p1 += (*mb_ptr2len)(p1) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065#endif
5066 }
5067
5068 /*
5069 * 4. If do_all is set, find next match.
5070 * Prevent endless loop with patterns that match empty
5071 * strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g.
5072 * But ":s/\n/#/" is OK.
5073 */
5074skip:
5075 /* We already know that we did the last subst when we are at
5076 * the end of the line, except that a pattern like
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00005077 * "bar\|\nfoo" may match at the NUL. "lnum" can be below
5078 * "line2" when there is a \zs in the pattern after a line
5079 * break. */
Bram Moolenaar8299df92004-07-10 09:47:34 +00005080 lastone = (skip_match
5081 || got_int
5082 || got_quit
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00005083 || lnum > line2
Bram Moolenaar8299df92004-07-10 09:47:34 +00005084 || !(do_all || do_again)
5085 || (sub_firstline[matchcol] == NUL && nmatch <= 1
5086 && !re_multiline(regmatch.regprog)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087 nmatch = -1;
5088
5089 /*
5090 * Replace the line in the buffer when needed. This is
5091 * skipped when there are more matches.
5092 * The check for nmatch_tl is needed for when multi-line
5093 * matching must replace the lines before trying to do another
5094 * match, otherwise "\@<=" won't work.
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00005095 * When the match starts below where we start searching also
5096 * need to replace the line first (using \zs after \n).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005097 */
5098 if (lastone
Bram Moolenaar071d4272004-06-13 20:20:40 +00005099 || nmatch_tl > 0
5100 || (nmatch = vim_regexec_multi(&regmatch, curwin,
Bram Moolenaar91a4e822008-01-19 14:59:58 +00005101 curbuf, sub_firstlnum,
5102 matchcol, NULL)) == 0
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00005103 || regmatch.startpos[0].lnum > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005104 {
5105 if (new_start != NULL)
5106 {
5107 /*
5108 * Copy the rest of the line, that didn't match.
5109 * "matchcol" has to be adjusted, we use the end of
5110 * the line as reference, because the substitute may
5111 * have changed the number of characters. Same for
5112 * "prev_matchcol".
5113 */
5114 STRCAT(new_start, sub_firstline + copycol);
5115 matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol;
5116 prev_matchcol = (colnr_T)STRLEN(sub_firstline)
5117 - prev_matchcol;
5118
5119 if (u_savesub(lnum) != OK)
5120 break;
5121 ml_replace(lnum, new_start, TRUE);
5122
5123 if (nmatch_tl > 0)
5124 {
5125 /*
5126 * Matched lines have now been substituted and are
5127 * useless, delete them. The part after the match
5128 * has been appended to new_start, we don't need
5129 * it in the buffer.
5130 */
5131 ++lnum;
5132 if (u_savedel(lnum, nmatch_tl) != OK)
5133 break;
5134 for (i = 0; i < nmatch_tl; ++i)
5135 ml_delete(lnum, (int)FALSE);
5136 mark_adjust(lnum, lnum + nmatch_tl - 1,
5137 (long)MAXLNUM, -nmatch_tl);
5138 if (do_ask)
5139 deleted_lines(lnum, nmatch_tl);
5140 --lnum;
5141 line2 -= nmatch_tl; /* nr of lines decreases */
5142 nmatch_tl = 0;
5143 }
5144
5145 /* When asking, undo is saved each time, must also set
5146 * changed flag each time. */
5147 if (do_ask)
5148 changed_bytes(lnum, 0);
5149 else
5150 {
5151 if (first_line == 0)
5152 first_line = lnum;
5153 last_line = lnum + 1;
5154 }
5155
5156 sub_firstlnum = lnum;
5157 vim_free(sub_firstline); /* free the temp buffer */
5158 sub_firstline = new_start;
5159 new_start = NULL;
5160 matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol;
5161 prev_matchcol = (colnr_T)STRLEN(sub_firstline)
5162 - prev_matchcol;
5163 copycol = 0;
5164 }
5165 if (nmatch == -1 && !lastone)
5166 nmatch = vim_regexec_multi(&regmatch, curwin, curbuf,
Bram Moolenaar91a4e822008-01-19 14:59:58 +00005167 sub_firstlnum, matchcol, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005168
5169 /*
5170 * 5. break if there isn't another match in this line
5171 */
5172 if (nmatch <= 0)
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00005173 {
5174 /* If the match found didn't start where we were
5175 * searching, do the next search in the line where we
5176 * found the match. */
5177 if (nmatch == -1)
5178 lnum -= regmatch.startpos[0].lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 break;
Bram Moolenaarbd7cc032008-01-09 21:40:50 +00005180 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005181 }
5182
5183 line_breakcheck();
5184 }
5185
5186 if (did_sub)
5187 ++sub_nlines;
Bram Moolenaarda2bd6f2008-09-14 19:41:30 +00005188 vim_free(new_start); /* for when substitute was cancelled */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189 vim_free(sub_firstline); /* free the copy of the original line */
5190 sub_firstline = NULL;
5191 }
5192
5193 line_breakcheck();
5194 }
5195
5196 if (first_line != 0)
5197 {
5198 /* Need to subtract the number of added lines from "last_line" to get
5199 * the line number before the change (same as adding the number of
5200 * deleted lines). */
5201 i = curbuf->b_ml.ml_line_count - old_line_count;
5202 changed_lines(first_line, 0, last_line - i, i);
5203 }
5204
5205outofmem:
5206 vim_free(sub_firstline); /* may have to free allocated copy of the line */
Bram Moolenaar05159a02005-02-26 23:04:13 +00005207
5208 /* ":s/pat//n" doesn't move the cursor */
5209 if (do_count)
5210 curwin->w_cursor = old_cursor;
5211
Bram Moolenaar46475522010-03-23 17:36:29 +01005212 if (sub_nsubs > start_nsubs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005213 {
5214 /* Set the '[ and '] marks. */
5215 curbuf->b_op_start.lnum = eap->line1;
5216 curbuf->b_op_end.lnum = line2;
5217 curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
5218
5219 if (!global_busy)
5220 {
Bram Moolenaar0faaeb82012-03-07 14:57:52 +01005221 if (!do_ask) /* when interactive leave cursor on the match */
5222 {
5223 if (endcolumn)
5224 coladvance((colnr_T)MAXCOL);
5225 else
5226 beginline(BL_WHITE | BL_FIX);
5227 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00005228 if (!do_sub_msg(do_count) && do_ask)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229 MSG("");
5230 }
5231 else
5232 global_need_beginline = TRUE;
5233 if (do_print)
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005234 print_line(curwin->w_cursor.lnum, do_number, do_list);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005235 }
5236 else if (!global_busy)
5237 {
5238 if (got_int) /* interrupted */
5239 EMSG(_(e_interr));
5240 else if (got_match) /* did find something but nothing substituted */
5241 MSG("");
5242 else if (do_error) /* nothing found */
5243 EMSG2(_(e_patnotf2), get_search_pat());
5244 }
5245
Bram Moolenaar8c4fbd12013-01-17 18:34:05 +01005246#ifdef FEAT_FOLDING
5247 if (do_ask && hasAnyFolding(curwin))
5248 /* Cursor position may require updating */
5249 changed_window_setting();
5250#endif
5251
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252 vim_free(regmatch.regprog);
5253}
5254
5255/*
5256 * Give message for number of substitutions.
5257 * Can also be used after a ":global" command.
5258 * Return TRUE if a message was given.
5259 */
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00005260 int
Bram Moolenaar05159a02005-02-26 23:04:13 +00005261do_sub_msg(count_only)
5262 int count_only; /* used 'n' flag for ":s" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263{
5264 /*
5265 * Only report substitutions when:
5266 * - more than 'report' substitutions
5267 * - command was typed by user, or number of changed lines > 'report'
5268 * - giving messages is not disabled by 'lazyredraw'
5269 */
Bram Moolenaar05159a02005-02-26 23:04:13 +00005270 if (((sub_nsubs > p_report && (KeyTyped || sub_nlines > 1 || p_report < 1))
5271 || count_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272 && messaging())
5273 {
5274 if (got_int)
5275 STRCPY(msg_buf, _("(Interrupted) "));
Bram Moolenaar0bc380a2010-07-10 13:52:13 +02005276 else
5277 *msg_buf = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005278 if (sub_nsubs == 1)
Bram Moolenaara800b422010-06-27 01:15:55 +02005279 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
Bram Moolenaar555b2802005-05-19 21:08:39 +00005280 "%s", count_only ? _("1 match") : _("1 substitution"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005281 else
Bram Moolenaara800b422010-06-27 01:15:55 +02005282 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
Bram Moolenaar05159a02005-02-26 23:04:13 +00005283 count_only ? _("%ld matches") : _("%ld substitutions"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005284 sub_nsubs);
5285 if (sub_nlines == 1)
Bram Moolenaara800b422010-06-27 01:15:55 +02005286 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
Bram Moolenaar555b2802005-05-19 21:08:39 +00005287 "%s", _(" on 1 line"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288 else
Bram Moolenaara800b422010-06-27 01:15:55 +02005289 vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
Bram Moolenaar555b2802005-05-19 21:08:39 +00005290 _(" on %ld lines"), (long)sub_nlines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291 if (msg(msg_buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005292 /* save message to display it after redraw */
Bram Moolenaar238a5642006-02-21 22:12:05 +00005293 set_keep_msg(msg_buf, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005294 return TRUE;
5295 }
5296 if (got_int)
5297 {
5298 EMSG(_(e_interr));
5299 return TRUE;
5300 }
5301 return FALSE;
5302}
5303
5304/*
5305 * Execute a global command of the form:
5306 *
5307 * g/pattern/X : execute X on all lines where pattern matches
5308 * v/pattern/X : execute X on all lines where pattern does not match
5309 *
5310 * where 'X' is an EX command
5311 *
5312 * The command character (as well as the trailing slash) is optional, and
5313 * is assumed to be 'p' if missing.
5314 *
5315 * This is implemented in two passes: first we scan the file for the pattern and
Bram Moolenaar7c0a86b2012-09-05 15:15:07 +02005316 * set a mark for each line that (not) matches. Secondly we execute the command
Bram Moolenaar071d4272004-06-13 20:20:40 +00005317 * for each line that has a mark. This is required because after deleting
5318 * lines we do not know where to search for the next match.
5319 */
5320 void
5321ex_global(eap)
5322 exarg_T *eap;
5323{
5324 linenr_T lnum; /* line number according to old situation */
Bram Moolenaar05159a02005-02-26 23:04:13 +00005325 int ndone = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005326 int type; /* first char of cmd: 'v' or 'g' */
5327 char_u *cmd; /* command argument */
5328
5329 char_u delim; /* delimiter, normally '/' */
5330 char_u *pat;
5331 regmmatch_T regmatch;
5332 int match;
5333 int which_pat;
5334
5335 if (global_busy)
5336 {
5337 EMSG(_("E147: Cannot do :global recursive")); /* will increment global_busy */
5338 return;
5339 }
5340
5341 if (eap->forceit) /* ":global!" is like ":vglobal" */
5342 type = 'v';
5343 else
5344 type = *eap->cmd;
5345 cmd = eap->arg;
5346 which_pat = RE_LAST; /* default: use last used regexp */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005347
5348 /*
5349 * undocumented vi feature:
5350 * "\/" and "\?": use previous search pattern.
5351 * "\&": use previous substitute pattern.
5352 */
5353 if (*cmd == '\\')
5354 {
5355 ++cmd;
5356 if (vim_strchr((char_u *)"/?&", *cmd) == NULL)
5357 {
5358 EMSG(_(e_backslash));
5359 return;
5360 }
5361 if (*cmd == '&')
5362 which_pat = RE_SUBST; /* use previous substitute pattern */
5363 else
5364 which_pat = RE_SEARCH; /* use previous search pattern */
5365 ++cmd;
5366 pat = (char_u *)"";
5367 }
5368 else if (*cmd == NUL)
5369 {
5370 EMSG(_("E148: Regular expression missing from global"));
5371 return;
5372 }
5373 else
5374 {
5375 delim = *cmd; /* get the delimiter */
5376 if (delim)
5377 ++cmd; /* skip delimiter if there is one */
5378 pat = cmd; /* remember start of pattern */
5379 cmd = skip_regexp(cmd, delim, p_magic, &eap->arg);
5380 if (cmd[0] == delim) /* end delimiter found */
5381 *cmd++ = NUL; /* replace it with a NUL */
5382 }
5383
5384#ifdef FEAT_FKMAP /* when in Farsi mode, reverse the character flow */
5385 if (p_altkeymap && curwin->w_p_rl)
5386 lrFswap(pat,0);
5387#endif
5388
5389 if (search_regcomp(pat, RE_BOTH, which_pat, SEARCH_HIS, &regmatch) == FAIL)
5390 {
5391 EMSG(_(e_invcmd));
5392 return;
5393 }
5394
5395 /*
5396 * pass 1: set marks for each (not) matching line
5397 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005398 for (lnum = eap->line1; lnum <= eap->line2 && !got_int; ++lnum)
5399 {
5400 /* a match on this line? */
Bram Moolenaar91a4e822008-01-19 14:59:58 +00005401 match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
5402 (colnr_T)0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005403 if ((type == 'g' && match) || (type == 'v' && !match))
5404 {
5405 ml_setmarked(lnum);
5406 ndone++;
5407 }
5408 line_breakcheck();
5409 }
5410
5411 /*
5412 * pass 2: execute the command for each line that has been marked
5413 */
5414 if (got_int)
5415 MSG(_(e_interr));
5416 else if (ndone == 0)
5417 {
5418 if (type == 'v')
Bram Moolenaar555b2802005-05-19 21:08:39 +00005419 smsg((char_u *)_("Pattern found in every line: %s"), pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005420 else
Bram Moolenaarc389fd32013-03-07 16:08:35 +01005421 smsg((char_u *)_("Pattern not found: %s"), pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005422 }
5423 else
5424 global_exe(cmd);
5425
5426 ml_clearmarked(); /* clear rest of the marks */
5427 vim_free(regmatch.regprog);
5428}
5429
5430/*
5431 * Execute "cmd" on lines marked with ml_setmarked().
5432 */
5433 void
5434global_exe(cmd)
5435 char_u *cmd;
5436{
Bram Moolenaarbb993222011-05-10 16:00:47 +02005437 linenr_T old_lcount; /* b_ml.ml_line_count before the command */
5438 buf_T *old_buf = curbuf; /* remember what buffer we started in */
5439 linenr_T lnum; /* line number according to old situation */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005440
5441 /*
5442 * Set current position only once for a global command.
5443 * If global_busy is set, setpcmark() will not do anything.
5444 * If there is an error, global_busy will be incremented.
5445 */
5446 setpcmark();
5447
5448 /* When the command writes a message, don't overwrite the command. */
5449 msg_didout = TRUE;
5450
Bram Moolenaard25bc232010-03-23 17:49:24 +01005451 sub_nsubs = 0;
5452 sub_nlines = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005453 global_need_beginline = FALSE;
5454 global_busy = 1;
5455 old_lcount = curbuf->b_ml.ml_line_count;
5456 while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1)
5457 {
5458 curwin->w_cursor.lnum = lnum;
5459 curwin->w_cursor.col = 0;
5460 if (*cmd == NUL || *cmd == '\n')
5461 do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT);
5462 else
5463 do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT);
5464 ui_breakcheck();
5465 }
5466
5467 global_busy = 0;
5468 if (global_need_beginline)
5469 beginline(BL_WHITE | BL_FIX);
5470 else
5471 check_cursor(); /* cursor may be beyond the end of the line */
5472
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005473 /* the cursor may not have moved in the text but a change in a previous
5474 * line may move it on the screen */
5475 changed_line_abv_curs();
5476
Bram Moolenaar071d4272004-06-13 20:20:40 +00005477 /* If it looks like no message was written, allow overwriting the
5478 * command with the report for number of changes. */
5479 if (msg_col == 0 && msg_scrolled == 0)
5480 msg_didout = FALSE;
5481
Bram Moolenaar45667512007-05-10 19:24:43 +00005482 /* If substitutes done, report number of substitutes, otherwise report
Bram Moolenaarbb993222011-05-10 16:00:47 +02005483 * number of extra or deleted lines.
5484 * Don't report extra or deleted lines in the edge case where the buffer
5485 * we are in after execution is different from the buffer we started in. */
5486 if (!do_sub_msg(FALSE) && curbuf == old_buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005487 msgmore(curbuf->b_ml.ml_line_count - old_lcount);
5488}
5489
5490#ifdef FEAT_VIMINFO
5491 int
5492read_viminfo_sub_string(virp, force)
5493 vir_T *virp;
5494 int force;
5495{
Bram Moolenaar3c2d6532011-02-01 13:48:53 +01005496 if (force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005497 vim_free(old_sub);
5498 if (force || old_sub == NULL)
5499 old_sub = viminfo_readstring(virp, 1, TRUE);
5500 return viminfo_readline(virp);
5501}
5502
5503 void
5504write_viminfo_sub_string(fp)
5505 FILE *fp;
5506{
5507 if (get_viminfo_parameter('/') != 0 && old_sub != NULL)
5508 {
Bram Moolenaar2f1e0502010-08-13 11:18:02 +02005509 fputs(_("\n# Last Substitute String:\n$"), fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005510 viminfo_writestring(fp, old_sub);
5511 }
5512}
5513#endif /* FEAT_VIMINFO */
5514
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00005515#if defined(EXITFREE) || defined(PROTO)
5516 void
5517free_old_sub()
5518{
5519 vim_free(old_sub);
5520}
5521#endif
5522
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523#if (defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)) || defined(PROTO)
5524/*
5525 * Set up for a tagpreview.
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00005526 * Return TRUE when it was created.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005527 */
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00005528 int
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00005529prepare_tagpreview(undo_sync)
5530 int undo_sync; /* sync undo when leaving the window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005531{
5532 win_T *wp;
5533
5534# ifdef FEAT_GUI
5535 need_mouse_correct = TRUE;
5536# endif
5537
5538 /*
5539 * If there is already a preview window open, use that one.
5540 */
5541 if (!curwin->w_p_pvw)
5542 {
5543 for (wp = firstwin; wp != NULL; wp = wp->w_next)
5544 if (wp->w_p_pvw)
5545 break;
5546 if (wp != NULL)
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00005547 win_enter(wp, undo_sync);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005548 else
5549 {
5550 /*
5551 * There is no preview window open yet. Create one.
5552 */
5553 if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0)
5554 == FAIL)
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00005555 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005556 curwin->w_p_pvw = TRUE;
5557 curwin->w_p_wfh = TRUE;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02005558 RESET_BINDING(curwin); /* don't take over 'scrollbind'
5559 and 'cursorbind' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005560# ifdef FEAT_DIFF
5561 curwin->w_p_diff = FALSE; /* no 'diff' */
5562# endif
5563# ifdef FEAT_FOLDING
5564 curwin->w_p_fdc = 0; /* no 'foldcolumn' */
5565# endif
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00005566 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005567 }
5568 }
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00005569 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005570}
5571
5572#endif
5573
5574
5575/*
5576 * ":help": open a read-only window on a help file
5577 */
5578 void
5579ex_help(eap)
5580 exarg_T *eap;
5581{
5582 char_u *arg;
5583 char_u *tag;
5584 FILE *helpfd; /* file descriptor of help file */
5585 int n;
5586 int i;
5587#ifdef FEAT_WINDOWS
5588 win_T *wp;
5589#endif
5590 int num_matches;
5591 char_u **matches;
5592 char_u *p;
5593 int empty_fnum = 0;
5594 int alt_fnum = 0;
5595 buf_T *buf;
5596#ifdef FEAT_MULTI_LANG
5597 int len;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005598 char_u *lang;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599#endif
Bram Moolenaar8f535582011-09-30 17:30:31 +02005600#ifdef FEAT_FOLDING
5601 int old_KeyTyped = KeyTyped;
5602#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005603
5604 if (eap != NULL)
5605 {
5606 /*
5607 * A ":help" command ends at the first LF, or at a '|' that is
5608 * followed by some text. Set nextcmd to the following command.
5609 */
5610 for (arg = eap->arg; *arg; ++arg)
5611 {
5612 if (*arg == '\n' || *arg == '\r'
5613 || (*arg == '|' && arg[1] != NUL && arg[1] != '|'))
5614 {
5615 *arg++ = NUL;
5616 eap->nextcmd = arg;
5617 break;
5618 }
5619 }
5620 arg = eap->arg;
5621
Bram Moolenaar3dbde622012-04-05 16:05:05 +02005622 if (eap->forceit && *arg == NUL && !curbuf->b_help)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623 {
5624 EMSG(_("E478: Don't panic!"));
5625 return;
5626 }
5627
5628 if (eap->skip) /* not executing commands */
5629 return;
5630 }
5631 else
5632 arg = (char_u *)"";
5633
5634 /* remove trailing blanks */
5635 p = arg + STRLEN(arg) - 1;
5636 while (p > arg && vim_iswhite(*p) && p[-1] != '\\')
5637 *p-- = NUL;
5638
5639#ifdef FEAT_MULTI_LANG
5640 /* Check for a specified language */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005641 lang = check_help_lang(arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005642#endif
5643
5644 /* When no argument given go to the index. */
5645 if (*arg == NUL)
5646 arg = (char_u *)"help.txt";
5647
5648 /*
5649 * Check if there is a match for the argument.
5650 */
5651 n = find_help_tags(arg, &num_matches, &matches,
5652 eap != NULL && eap->forceit);
5653
5654 i = 0;
5655#ifdef FEAT_MULTI_LANG
5656 if (n != FAIL && lang != NULL)
5657 /* Find first item with the requested language. */
5658 for (i = 0; i < num_matches; ++i)
5659 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005660 len = (int)STRLEN(matches[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661 if (len > 3 && matches[i][len - 3] == '@'
5662 && STRICMP(matches[i] + len - 2, lang) == 0)
5663 break;
5664 }
5665#endif
5666 if (i >= num_matches || n == FAIL)
5667 {
5668#ifdef FEAT_MULTI_LANG
5669 if (lang != NULL)
5670 EMSG3(_("E661: Sorry, no '%s' help for %s"), lang, arg);
5671 else
5672#endif
5673 EMSG2(_("E149: Sorry, no help for %s"), arg);
5674 if (n != FAIL)
5675 FreeWild(num_matches, matches);
5676 return;
5677 }
5678
5679 /* The first match (in the requested language) is the best match. */
5680 tag = vim_strsave(matches[i]);
5681 FreeWild(num_matches, matches);
5682
5683#ifdef FEAT_GUI
5684 need_mouse_correct = TRUE;
5685#endif
5686
5687 /*
5688 * Re-use an existing help window or open a new one.
Bram Moolenaar2a3f7ee2006-02-23 21:34:44 +00005689 * Always open a new one for ":tab help".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005690 */
Bram Moolenaar2a3f7ee2006-02-23 21:34:44 +00005691 if (!curwin->w_buffer->b_help
5692#ifdef FEAT_WINDOWS
5693 || cmdmod.tab != 0
5694#endif
5695 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696 {
5697#ifdef FEAT_WINDOWS
Bram Moolenaar2a3f7ee2006-02-23 21:34:44 +00005698 if (cmdmod.tab != 0)
5699 wp = NULL;
5700 else
5701 for (wp = firstwin; wp != NULL; wp = wp->w_next)
5702 if (wp->w_buffer != NULL && wp->w_buffer->b_help)
5703 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005704 if (wp != NULL && wp->w_buffer->b_nwindows > 0)
5705 win_enter(wp, TRUE);
5706 else
5707#endif
5708 {
5709 /*
5710 * There is no help window yet.
5711 * Try to open the file specified by the "helpfile" option.
5712 */
5713 if ((helpfd = mch_fopen((char *)p_hf, READBIN)) == NULL)
5714 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00005715 smsg((char_u *)_("Sorry, help file \"%s\" not found"), p_hf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005716 goto erret;
5717 }
5718 fclose(helpfd);
5719
5720#ifdef FEAT_WINDOWS
5721 /* Split off help window; put it at far top if no position
Bram Moolenaar2a3f7ee2006-02-23 21:34:44 +00005722 * specified, the current window is vertically split and
5723 * narrow. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724 n = WSP_HELP;
5725# ifdef FEAT_VERTSPLIT
5726 if (cmdmod.split == 0 && curwin->w_width != Columns
Bram Moolenaar2a3f7ee2006-02-23 21:34:44 +00005727 && curwin->w_width < 80)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005728 n |= WSP_TOP;
5729# endif
5730 if (win_split(0, n) == FAIL)
Bram Moolenaar2a3f7ee2006-02-23 21:34:44 +00005731 goto erret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005732#else
5733 /* use current window */
5734 if (!can_abandon(curbuf, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735 goto erret;
Bram Moolenaar2a3f7ee2006-02-23 21:34:44 +00005736#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737
5738#ifdef FEAT_WINDOWS
5739 if (curwin->w_height < p_hh)
5740 win_setheight((int)p_hh);
5741#endif
5742
5743 /*
5744 * Open help file (do_ecmd() will set b_help flag, readfile() will
5745 * set b_p_ro flag).
5746 * Set the alternate file to the previously edited file.
5747 */
5748 alt_fnum = curbuf->b_fnum;
5749 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_LASTL,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00005750 ECMD_HIDE + ECMD_SET_HELP,
5751#ifdef FEAT_WINDOWS
5752 NULL /* buffer is still open, don't store info */
5753#else
5754 curwin
5755#endif
5756 );
Bram Moolenaard4755bb2004-09-02 19:12:26 +00005757 if (!cmdmod.keepalt)
5758 curwin->w_alt_fnum = alt_fnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005759 empty_fnum = curbuf->b_fnum;
5760 }
5761 }
5762
5763 if (!p_im)
5764 restart_edit = 0; /* don't want insert mode in help file */
5765
Bram Moolenaar8f535582011-09-30 17:30:31 +02005766#ifdef FEAT_FOLDING
5767 /* Restore KeyTyped, setting 'filetype=help' may reset it.
5768 * It is needed for do_tag top open folds under the cursor. */
5769 KeyTyped = old_KeyTyped;
5770#endif
5771
Bram Moolenaar071d4272004-06-13 20:20:40 +00005772 if (tag != NULL)
5773 do_tag(tag, DT_HELP, 1, FALSE, TRUE);
5774
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005775 /* Delete the empty buffer if we're not using it. Careful: autocommands
5776 * may have jumped to another window, check that the buffer is not in a
5777 * window. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005778 if (empty_fnum != 0 && curbuf->b_fnum != empty_fnum)
5779 {
5780 buf = buflist_findnr(empty_fnum);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005781 if (buf != NULL && buf->b_nwindows == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005782 wipe_buffer(buf, TRUE);
5783 }
5784
5785 /* keep the previous alternate file */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00005786 if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && !cmdmod.keepalt)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787 curwin->w_alt_fnum = alt_fnum;
5788
5789erret:
5790 vim_free(tag);
5791}
5792
5793
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005794#if defined(FEAT_MULTI_LANG) || defined(PROTO)
5795/*
5796 * In an argument search for a language specifiers in the form "@xx".
5797 * Changes the "@" to NUL if found, and returns a pointer to "xx".
5798 * Returns NULL if not found.
5799 */
5800 char_u *
5801check_help_lang(arg)
5802 char_u *arg;
5803{
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005804 int len = (int)STRLEN(arg);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005805
5806 if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2])
5807 && ASCII_ISALPHA(arg[len - 1]))
5808 {
5809 arg[len - 3] = NUL; /* remove the '@' */
5810 return arg + len - 2;
5811 }
5812 return NULL;
5813}
5814#endif
5815
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816/*
5817 * Return a heuristic indicating how well the given string matches. The
5818 * smaller the number, the better the match. This is the order of priorities,
5819 * from best match to worst match:
5820 * - Match with least alpha-numeric characters is better.
5821 * - Match with least total characters is better.
5822 * - Match towards the start is better.
5823 * - Match starting with "+" is worse (feature instead of command)
5824 * Assumption is made that the matched_string passed has already been found to
5825 * match some string for which help is requested. webb.
5826 */
5827 int
5828help_heuristic(matched_string, offset, wrong_case)
5829 char_u *matched_string;
5830 int offset; /* offset for match */
5831 int wrong_case; /* no matching case */
5832{
5833 int num_letters;
5834 char_u *p;
5835
5836 num_letters = 0;
5837 for (p = matched_string; *p; p++)
5838 if (ASCII_ISALNUM(*p))
5839 num_letters++;
5840
5841 /*
5842 * Multiply the number of letters by 100 to give it a much bigger
5843 * weighting than the number of characters.
5844 * If there only is a match while ignoring case, add 5000.
5845 * If the match starts in the middle of a word, add 10000 to put it
5846 * somewhere in the last half.
5847 * If the match is more than 2 chars from the start, multiply by 200 to
5848 * put it after matches at the start.
5849 */
5850 if (ASCII_ISALNUM(matched_string[offset]) && offset > 0
5851 && ASCII_ISALNUM(matched_string[offset - 1]))
5852 offset += 10000;
5853 else if (offset > 2)
5854 offset *= 200;
5855 if (wrong_case)
5856 offset += 5000;
5857 /* Features are less interesting than the subjects themselves, but "+"
5858 * alone is not a feature. */
5859 if (matched_string[0] == '+' && matched_string[1] != NUL)
5860 offset += 100;
5861 return (int)(100 * num_letters + STRLEN(matched_string) + offset);
5862}
5863
5864/*
5865 * Compare functions for qsort() below, that checks the help heuristics number
5866 * that has been put after the tagname by find_tags().
5867 */
5868 static int
5869#ifdef __BORLANDC__
5870_RTLENTRYF
5871#endif
5872help_compare(s1, s2)
5873 const void *s1;
5874 const void *s2;
5875{
5876 char *p1;
5877 char *p2;
5878
5879 p1 = *(char **)s1 + strlen(*(char **)s1) + 1;
5880 p2 = *(char **)s2 + strlen(*(char **)s2) + 1;
5881 return strcmp(p1, p2);
5882}
5883
5884/*
5885 * Find all help tags matching "arg", sort them and return in matches[], with
5886 * the number of matches in num_matches.
5887 * The matches will be sorted with a "best" match algorithm.
5888 * When "keep_lang" is TRUE try keeping the language of the current buffer.
5889 */
5890 int
5891find_help_tags(arg, num_matches, matches, keep_lang)
5892 char_u *arg;
5893 int *num_matches;
5894 char_u ***matches;
5895 int keep_lang;
5896{
5897 char_u *s, *d;
5898 int i;
5899 static char *(mtable[]) = {"*", "g*", "[*", "]*", ":*",
Bram Moolenaar231334e2005-07-25 20:46:57 +00005900 "/*", "/\\*", "\"*", "**",
Bram Moolenaar117f2c42013-01-17 14:09:44 +01005901 "cpo-*", "/\\(\\)",
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00005902 "?", ":?", "?<CR>", "g?", "g?g?", "g??", "z?",
Bram Moolenaarf4630b62005-05-20 21:31:17 +00005903 "/\\?", "/\\z(\\)", "\\=", ":s\\=",
Bram Moolenaar071d4272004-06-13 20:20:40 +00005904 "[count]", "[quotex]", "[range]",
5905 "[pattern]", "\\|", "\\%$"};
5906 static char *(rtable[]) = {"star", "gstar", "[star", "]star", ":star",
Bram Moolenaar231334e2005-07-25 20:46:57 +00005907 "/star", "/\\\\star", "quotestar", "starstar",
Bram Moolenaar117f2c42013-01-17 14:09:44 +01005908 "cpo-star", "/\\\\(\\\\)",
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00005909 "?", ":?", "?<CR>", "g?", "g?g?", "g??", "z?",
Bram Moolenaarf4630b62005-05-20 21:31:17 +00005910 "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=",
Bram Moolenaar071d4272004-06-13 20:20:40 +00005911 "\\[count]", "\\[quotex]", "\\[range]",
5912 "\\[pattern]", "\\\\bar", "/\\\\%\\$"};
5913 int flags;
5914
5915 d = IObuff; /* assume IObuff is long enough! */
5916
5917 /*
5918 * Recognize a few exceptions to the rule. Some strings that contain '*'
5919 * with "star". Otherwise '*' is recognized as a wildcard.
5920 */
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00005921 for (i = (int)(sizeof(mtable) / sizeof(char *)); --i >= 0; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00005922 if (STRCMP(arg, mtable[i]) == 0)
5923 {
5924 STRCPY(d, rtable[i]);
5925 break;
5926 }
5927
5928 if (i < 0) /* no match in table */
5929 {
5930 /* Replace "\S" with "/\\S", etc. Otherwise every tag is matched.
5931 * Also replace "\%^" and "\%(", they match every tag too.
5932 * Also "\zs", "\z1", etc.
5933 * Also "\@<", "\@=", "\@<=", etc.
5934 * And also "\_$" and "\_^". */
5935 if (arg[0] == '\\'
5936 && ((arg[1] != NUL && arg[2] == NUL)
5937 || (vim_strchr((char_u *)"%_z@", arg[1]) != NULL
5938 && arg[2] != NUL)))
5939 {
5940 STRCPY(d, "/\\\\");
5941 STRCPY(d + 3, arg + 1);
5942 /* Check for "/\\_$", should be "/\\_\$" */
5943 if (d[3] == '_' && d[4] == '$')
5944 STRCPY(d + 4, "\\$");
5945 }
5946 else
5947 {
Bram Moolenaar7c0a86b2012-09-05 15:15:07 +02005948 /* Replace:
5949 * "[:...:]" with "\[:...:]"
5950 * "[++...]" with "\[++...]"
5951 * "\{" with "\\{"
5952 */
5953 if ((arg[0] == '[' && (arg[1] == ':'
5954 || (arg[1] == '+' && arg[2] == '+')))
5955 || (arg[0] == '\\' && arg[1] == '{'))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005956 *d++ = '\\';
5957
5958 for (s = arg; *s; ++s)
5959 {
5960 /*
5961 * Replace "|" with "bar" and '"' with "quote" to match the name of
5962 * the tags for these commands.
5963 * Replace "*" with ".*" and "?" with "." to match command line
5964 * completion.
5965 * Insert a backslash before '~', '$' and '.' to avoid their
5966 * special meaning.
5967 */
5968 if (d - IObuff > IOSIZE - 10) /* getting too long!? */
5969 break;
5970 switch (*s)
5971 {
5972 case '|': STRCPY(d, "bar");
5973 d += 3;
5974 continue;
5975 case '"': STRCPY(d, "quote");
5976 d += 5;
5977 continue;
5978 case '*': *d++ = '.';
5979 break;
5980 case '?': *d++ = '.';
5981 continue;
5982 case '$':
5983 case '.':
5984 case '~': *d++ = '\\';
5985 break;
5986 }
5987
5988 /*
5989 * Replace "^x" by "CTRL-X". Don't do this for "^_" to make
5990 * ":help i_^_CTRL-D" work.
5991 * Insert '-' before and after "CTRL-X" when applicable.
5992 */
5993 if (*s < ' ' || (*s == '^' && s[1] && (ASCII_ISALPHA(s[1])
5994 || vim_strchr((char_u *)"?@[\\]^", s[1]) != NULL)))
5995 {
5996 if (d > IObuff && d[-1] != '_')
5997 *d++ = '_'; /* prepend a '_' */
5998 STRCPY(d, "CTRL-");
5999 d += 5;
6000 if (*s < ' ')
6001 {
6002#ifdef EBCDIC
6003 *d++ = CtrlChar(*s);
6004#else
6005 *d++ = *s + '@';
6006#endif
6007 if (d[-1] == '\\')
6008 *d++ = '\\'; /* double a backslash */
6009 }
6010 else
6011 *d++ = *++s;
6012 if (s[1] != NUL && s[1] != '_')
6013 *d++ = '_'; /* append a '_' */
6014 continue;
6015 }
6016 else if (*s == '^') /* "^" or "CTRL-^" or "^_" */
6017 *d++ = '\\';
6018
6019 /*
6020 * Insert a backslash before a backslash after a slash, for search
6021 * pattern tags: "/\|" --> "/\\|".
6022 */
6023 else if (s[0] == '\\' && s[1] != '\\'
6024 && *arg == '/' && s == arg + 1)
6025 *d++ = '\\';
6026
6027 /* "CTRL-\_" -> "CTRL-\\_" to avoid the special meaning of "\_" in
6028 * "CTRL-\_CTRL-N" */
6029 if (STRNICMP(s, "CTRL-\\_", 7) == 0)
6030 {
6031 STRCPY(d, "CTRL-\\\\");
6032 d += 7;
6033 s += 6;
6034 }
6035
6036 *d++ = *s;
6037
6038 /*
6039 * If tag starts with ', toss everything after a second '. Fixes
6040 * CTRL-] on 'option'. (would include the trailing '.').
6041 */
6042 if (*s == '\'' && s > arg && *arg == '\'')
6043 break;
6044 }
6045 *d = NUL;
Bram Moolenaar720ce532012-04-25 12:57:28 +02006046
6047 if (*IObuff == '`')
6048 {
6049 if (d > IObuff + 2 && d[-1] == '`')
6050 {
6051 /* remove the backticks from `command` */
6052 mch_memmove(IObuff, IObuff + 1, STRLEN(IObuff));
6053 d[-2] = NUL;
6054 }
6055 else if (d > IObuff + 3 && d[-2] == '`' && d[-1] == ',')
6056 {
6057 /* remove the backticks and comma from `command`, */
6058 mch_memmove(IObuff, IObuff + 1, STRLEN(IObuff));
6059 d[-3] = NUL;
6060 }
6061 else if (d > IObuff + 4 && d[-3] == '`'
6062 && d[-2] == '\\' && d[-1] == '.')
6063 {
6064 /* remove the backticks and dot from `command`\. */
6065 mch_memmove(IObuff, IObuff + 1, STRLEN(IObuff));
6066 d[-4] = NUL;
6067 }
6068 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069 }
6070 }
6071
6072 *matches = (char_u **)"";
6073 *num_matches = 0;
6074 flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE;
6075 if (keep_lang)
6076 flags |= TAG_KEEP_LANG;
Bram Moolenaarc62e2fe2008-08-06 13:03:07 +00006077 if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00006078 && *num_matches > 0)
Bram Moolenaarc62e2fe2008-08-06 13:03:07 +00006079 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006080 /* Sort the matches found on the heuristic number that is after the
6081 * tag name. */
6082 qsort((void *)*matches, (size_t)*num_matches,
6083 sizeof(char_u *), help_compare);
Bram Moolenaarc62e2fe2008-08-06 13:03:07 +00006084 /* Delete more than TAG_MANY to reduce the size of the listing. */
6085 while (*num_matches > TAG_MANY)
6086 vim_free((*matches)[--*num_matches]);
6087 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006088 return OK;
6089}
6090
6091/*
6092 * After reading a help file: May cleanup a help buffer when syntax
6093 * highlighting is not used.
6094 */
6095 void
6096fix_help_buffer()
6097{
6098 linenr_T lnum;
6099 char_u *line;
6100 int in_example = FALSE;
6101 int len;
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006102 char_u *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006103 char_u *p;
6104 char_u *rt;
6105 int mustfree;
6106
6107 /* set filetype to "help". */
6108 set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
6109
6110#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02006111 if (!syntax_present(curwin))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006112#endif
6113 {
6114 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
6115 {
6116 line = ml_get_buf(curbuf, lnum, FALSE);
6117 len = (int)STRLEN(line);
6118 if (in_example && len > 0 && !vim_iswhite(line[0]))
6119 {
6120 /* End of example: non-white or '<' in first column. */
6121 if (line[0] == '<')
6122 {
6123 /* blank-out a '<' in the first column */
6124 line = ml_get_buf(curbuf, lnum, TRUE);
6125 line[0] = ' ';
6126 }
6127 in_example = FALSE;
6128 }
6129 if (!in_example && len > 0)
6130 {
6131 if (line[len - 1] == '>' && (len == 1 || line[len - 2] == ' '))
6132 {
6133 /* blank-out a '>' in the last column (start of example) */
6134 line = ml_get_buf(curbuf, lnum, TRUE);
6135 line[len - 1] = ' ';
6136 in_example = TRUE;
6137 }
6138 else if (line[len - 1] == '~')
6139 {
6140 /* blank-out a '~' at the end of line (header marker) */
6141 line = ml_get_buf(curbuf, lnum, TRUE);
6142 line[len - 1] = ' ';
6143 }
6144 }
6145 }
6146 }
6147
6148 /*
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006149 * In the "help.txt" and "help.abx" file, add the locally added help
6150 * files. This uses the very first line in the help file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006151 */
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006152 fname = gettail(curbuf->b_fname);
6153 if (fnamecmp(fname, "help.txt") == 0
6154#ifdef FEAT_MULTI_LANG
6155 || (fnamencmp(fname, "help.", 5) == 0
6156 && ASCII_ISALPHA(fname[5])
6157 && ASCII_ISALPHA(fname[6])
6158 && TOLOWER_ASC(fname[7]) == 'x'
6159 && fname[8] == NUL)
6160#endif
6161 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006162 {
6163 for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum)
6164 {
6165 line = ml_get_buf(curbuf, lnum, FALSE);
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006166 if (strstr((char *)line, "*local-additions*") == NULL)
6167 continue;
6168
6169 /* Go through all directories in 'runtimepath', skipping
6170 * $VIMRUNTIME. */
6171 p = p_rtp;
6172 while (*p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006173 {
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006174 copy_option_part(&p, NameBuff, MAXPATHL, ",");
6175 mustfree = FALSE;
6176 rt = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
6177 if (fullpathcmp(rt, NameBuff, FALSE) != FPC_SAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006178 {
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006179 int fcount;
6180 char_u **fnames;
6181 FILE *fd;
6182 char_u *s;
6183 int fi;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006184#ifdef FEAT_MBYTE
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006185 vimconv_T vc;
6186 char_u *cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006187#endif
6188
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006189 /* Find all "doc/ *.txt" files in this directory. */
6190 add_pathsep(NameBuff);
6191#ifdef FEAT_MULTI_LANG
6192 STRCAT(NameBuff, "doc/*.??[tx]");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193#else
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006194 STRCAT(NameBuff, "doc/*.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006195#endif
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006196 if (gen_expand_wildcards(1, &NameBuff, &fcount,
6197 &fnames, EW_FILE|EW_SILENT) == OK
6198 && fcount > 0)
6199 {
6200#ifdef FEAT_MULTI_LANG
6201 int i1;
6202 int i2;
6203 char_u *f1;
6204 char_u *f2;
6205 char_u *t1;
6206 char_u *e1;
6207 char_u *e2;
6208
6209 /* If foo.abx is found use it instead of foo.txt in
6210 * the same directory. */
6211 for (i1 = 0; i1 < fcount; ++i1)
6212 {
6213 for (i2 = 0; i2 < fcount; ++i2)
6214 {
6215 if (i1 == i2)
6216 continue;
6217 if (fnames[i1] == NULL || fnames[i2] == NULL)
6218 continue;
6219 f1 = fnames[i1];
6220 f2 = fnames[i2];
6221 t1 = gettail(f1);
6222 if (fnamencmp(f1, f2, t1 - f1) != 0)
6223 continue;
6224 e1 = vim_strrchr(t1, '.');
6225 e2 = vim_strrchr(gettail(f2), '.');
6226 if (e1 == NUL || e2 == NUL)
6227 continue;
6228 if (fnamecmp(e1, ".txt") != 0
6229 && fnamecmp(e1, fname + 4) != 0)
6230 {
6231 /* Not .txt and not .abx, remove it. */
6232 vim_free(fnames[i1]);
6233 fnames[i1] = NULL;
6234 continue;
6235 }
6236 if (fnamencmp(f1, f2, e1 - f1) != 0)
6237 continue;
6238 if (fnamecmp(e1, ".txt") == 0
6239 && fnamecmp(e2, fname + 4) == 0)
6240 {
6241 /* use .abx instead of .txt */
6242 vim_free(fnames[i1]);
6243 fnames[i1] = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244 }
6245 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246 }
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006247#endif
6248 for (fi = 0; fi < fcount; ++fi)
6249 {
6250 if (fnames[fi] == NULL)
6251 continue;
6252 fd = mch_fopen((char *)fnames[fi], "r");
6253 if (fd != NULL)
6254 {
6255 vim_fgets(IObuff, IOSIZE, fd);
6256 if (IObuff[0] == '*'
6257 && (s = vim_strchr(IObuff + 1, '*'))
6258 != NULL)
6259 {
6260#ifdef FEAT_MBYTE
6261 int this_utf = MAYBE;
6262#endif
6263 /* Change tag definition to a
6264 * reference and remove <CR>/<NL>. */
6265 IObuff[0] = '|';
6266 *s = '|';
6267 while (*s != NUL)
6268 {
6269 if (*s == '\r' || *s == '\n')
6270 *s = NUL;
6271#ifdef FEAT_MBYTE
6272 /* The text is utf-8 when a byte
6273 * above 127 is found and no
6274 * illegal byte sequence is found.
6275 */
6276 if (*s >= 0x80 && this_utf != FALSE)
6277 {
6278 int l;
6279
6280 this_utf = TRUE;
6281 l = utf_ptr2len(s);
6282 if (l == 1)
6283 this_utf = FALSE;
6284 s += l - 1;
6285 }
6286#endif
6287 ++s;
6288 }
6289#ifdef FEAT_MBYTE
6290 /* The help file is latin1 or utf-8;
6291 * conversion to the current
6292 * 'encoding' may be required. */
6293 vc.vc_type = CONV_NONE;
6294 convert_setup(&vc, (char_u *)(
6295 this_utf == TRUE ? "utf-8"
6296 : "latin1"), p_enc);
6297 if (vc.vc_type == CONV_NONE)
6298 /* No conversion needed. */
6299 cp = IObuff;
6300 else
6301 {
6302 /* Do the conversion. If it fails
6303 * use the unconverted text. */
6304 cp = string_convert(&vc, IObuff,
6305 NULL);
6306 if (cp == NULL)
6307 cp = IObuff;
6308 }
6309 convert_setup(&vc, NULL, NULL);
6310
6311 ml_append(lnum, cp, (colnr_T)0, FALSE);
6312 if (cp != IObuff)
6313 vim_free(cp);
6314#else
6315 ml_append(lnum, IObuff, (colnr_T)0,
6316 FALSE);
6317#endif
6318 ++lnum;
6319 }
6320 fclose(fd);
6321 }
6322 }
6323 FreeWild(fcount, fnames);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006324 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325 }
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006326 if (mustfree)
6327 vim_free(rt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006328 }
Bram Moolenaar667b4d22011-10-20 18:17:42 +02006329 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006330 }
6331 }
6332}
6333
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006334/*
6335 * ":exusage"
6336 */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006337 void
6338ex_exusage(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00006339 exarg_T *eap UNUSED;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006340{
6341 do_cmdline_cmd((char_u *)"help ex-cmd-index");
6342}
6343
6344/*
6345 * ":viusage"
6346 */
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006347 void
6348ex_viusage(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00006349 exarg_T *eap UNUSED;
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006350{
6351 do_cmdline_cmd((char_u *)"help normal-index");
6352}
6353
Bram Moolenaar071d4272004-06-13 20:20:40 +00006354#if defined(FEAT_EX_EXTRA) || defined(PROTO)
Bram Moolenaar426e5c92008-01-11 20:02:02 +00006355static void helptags_one __ARGS((char_u *dir, char_u *ext, char_u *lang, int add_help_tags));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006356
6357/*
6358 * ":helptags"
6359 */
6360 void
6361ex_helptags(eap)
6362 exarg_T *eap;
6363{
6364 garray_T ga;
6365 int i, j;
6366 int len;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006367#ifdef FEAT_MULTI_LANG
Bram Moolenaar071d4272004-06-13 20:20:40 +00006368 char_u lang[2];
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006369#endif
Bram Moolenaar0e253142008-01-13 12:31:34 +00006370 expand_T xpc;
6371 char_u *dirname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006372 char_u ext[5];
6373 char_u fname[8];
6374 int filecount;
6375 char_u **files;
Bram Moolenaar426e5c92008-01-11 20:02:02 +00006376 int add_help_tags = FALSE;
6377
6378 /* Check for ":helptags ++t {dir}". */
6379 if (STRNCMP(eap->arg, "++t", 3) == 0 && vim_iswhite(eap->arg[3]))
6380 {
6381 add_help_tags = TRUE;
6382 eap->arg = skipwhite(eap->arg + 3);
6383 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006384
Bram Moolenaar0e253142008-01-13 12:31:34 +00006385 ExpandInit(&xpc);
6386 xpc.xp_context = EXPAND_DIRECTORIES;
6387 dirname = ExpandOne(&xpc, eap->arg, NULL,
6388 WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
6389 if (dirname == NULL || !mch_isdir(dirname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390 {
6391 EMSG2(_("E150: Not a directory: %s"), eap->arg);
6392 return;
6393 }
6394
6395#ifdef FEAT_MULTI_LANG
Bram Moolenaar442b5c42012-11-28 16:06:22 +01006396 /* Get a list of all files in the help directory and in subdirectories. */
Bram Moolenaar0e253142008-01-13 12:31:34 +00006397 STRCPY(NameBuff, dirname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006398 add_pathsep(NameBuff);
Bram Moolenaar442b5c42012-11-28 16:06:22 +01006399 STRCAT(NameBuff, "**");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006400 if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
6401 EW_FILE|EW_SILENT) == FAIL
6402 || filecount == 0)
6403 {
6404 EMSG2("E151: No match: %s", NameBuff);
Bram Moolenaar0e253142008-01-13 12:31:34 +00006405 vim_free(dirname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006406 return;
6407 }
6408
6409 /* Go over all files in the directory to find out what languages are
6410 * present. */
6411 ga_init2(&ga, 1, 10);
6412 for (i = 0; i < filecount; ++i)
6413 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006414 len = (int)STRLEN(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006415 if (len > 4)
6416 {
6417 if (STRICMP(files[i] + len - 4, ".txt") == 0)
6418 {
6419 /* ".txt" -> language "en" */
6420 lang[0] = 'e';
6421 lang[1] = 'n';
6422 }
6423 else if (files[i][len - 4] == '.'
6424 && ASCII_ISALPHA(files[i][len - 3])
6425 && ASCII_ISALPHA(files[i][len - 2])
6426 && TOLOWER_ASC(files[i][len - 1]) == 'x')
6427 {
6428 /* ".abx" -> language "ab" */
6429 lang[0] = TOLOWER_ASC(files[i][len - 3]);
6430 lang[1] = TOLOWER_ASC(files[i][len - 2]);
6431 }
6432 else
6433 continue;
6434
6435 /* Did we find this language already? */
6436 for (j = 0; j < ga.ga_len; j += 2)
6437 if (STRNCMP(lang, ((char_u *)ga.ga_data) + j, 2) == 0)
6438 break;
6439 if (j == ga.ga_len)
6440 {
6441 /* New language, add it. */
6442 if (ga_grow(&ga, 2) == FAIL)
6443 break;
6444 ((char_u *)ga.ga_data)[ga.ga_len++] = lang[0];
6445 ((char_u *)ga.ga_data)[ga.ga_len++] = lang[1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006446 }
6447 }
6448 }
6449
6450 /*
6451 * Loop over the found languages to generate a tags file for each one.
6452 */
6453 for (j = 0; j < ga.ga_len; j += 2)
6454 {
6455 STRCPY(fname, "tags-xx");
6456 fname[5] = ((char_u *)ga.ga_data)[j];
6457 fname[6] = ((char_u *)ga.ga_data)[j + 1];
6458 if (fname[5] == 'e' && fname[6] == 'n')
6459 {
6460 /* English is an exception: use ".txt" and "tags". */
6461 fname[4] = NUL;
6462 STRCPY(ext, ".txt");
6463 }
6464 else
6465 {
6466 /* Language "ab" uses ".abx" and "tags-ab". */
6467 STRCPY(ext, ".xxx");
6468 ext[1] = fname[5];
6469 ext[2] = fname[6];
6470 }
Bram Moolenaar0e253142008-01-13 12:31:34 +00006471 helptags_one(dirname, ext, fname, add_help_tags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006472 }
6473
6474 ga_clear(&ga);
6475 FreeWild(filecount, files);
6476
6477#else
6478 /* No language support, just use "*.txt" and "tags". */
Bram Moolenaar0e253142008-01-13 12:31:34 +00006479 helptags_one(dirname, (char_u *)".txt", (char_u *)"tags", add_help_tags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006480#endif
Bram Moolenaar0e253142008-01-13 12:31:34 +00006481 vim_free(dirname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006482}
6483
6484 static void
Bram Moolenaar426e5c92008-01-11 20:02:02 +00006485helptags_one(dir, ext, tagfname, add_help_tags)
6486 char_u *dir; /* doc directory */
6487 char_u *ext; /* suffix, ".txt", ".itx", ".frx", etc. */
Bram Moolenaar442b5c42012-11-28 16:06:22 +01006488 char_u *tagfname; /* "tags" for English, "tags-fr" for French. */
6489 int add_help_tags; /* add "help-tags" tag */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006490{
6491 FILE *fd_tags;
6492 FILE *fd;
6493 garray_T ga;
6494 int filecount;
6495 char_u **files;
6496 char_u *p1, *p2;
6497 int fi;
6498 char_u *s;
6499 int i;
6500 char_u *fname;
Bram Moolenaar442b5c42012-11-28 16:06:22 +01006501 int dirlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006502# ifdef FEAT_MBYTE
6503 int utf8 = MAYBE;
6504 int this_utf8;
6505 int firstline;
6506 int mix = FALSE; /* detected mixed encodings */
6507# endif
6508
6509 /*
6510 * Find all *.txt files.
6511 */
Bram Moolenaar862cfa32012-11-29 20:10:00 +01006512 dirlen = (int)STRLEN(dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006513 STRCPY(NameBuff, dir);
Bram Moolenaar442b5c42012-11-28 16:06:22 +01006514 STRCAT(NameBuff, "/**/*");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006515 STRCAT(NameBuff, ext);
6516 if (gen_expand_wildcards(1, &NameBuff, &filecount, &files,
6517 EW_FILE|EW_SILENT) == FAIL
6518 || filecount == 0)
6519 {
6520 if (!got_int)
6521 EMSG2("E151: No match: %s", NameBuff);
6522 return;
6523 }
6524
6525 /*
6526 * Open the tags file for writing.
6527 * Do this before scanning through all the files.
6528 */
6529 STRCPY(NameBuff, dir);
6530 add_pathsep(NameBuff);
6531 STRCAT(NameBuff, tagfname);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00006532 fd_tags = mch_fopen((char *)NameBuff, "w");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533 if (fd_tags == NULL)
6534 {
6535 EMSG2(_("E152: Cannot open %s for writing"), NameBuff);
6536 FreeWild(filecount, files);
6537 return;
6538 }
6539
6540 /*
Bram Moolenaar426e5c92008-01-11 20:02:02 +00006541 * If using the "++t" argument or generating tags for "$VIMRUNTIME/doc"
6542 * add the "help-tags" tag.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006543 */
6544 ga_init2(&ga, (int)sizeof(char_u *), 100);
Bram Moolenaar426e5c92008-01-11 20:02:02 +00006545 if (add_help_tags || fullpathcmp((char_u *)"$VIMRUNTIME/doc",
6546 dir, FALSE) == FPC_SAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006547 {
6548 if (ga_grow(&ga, 1) == FAIL)
6549 got_int = TRUE;
6550 else
6551 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006552 s = alloc(18 + (unsigned)STRLEN(tagfname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006553 if (s == NULL)
6554 got_int = TRUE;
6555 else
6556 {
6557 sprintf((char *)s, "help-tags\t%s\t1\n", tagfname);
6558 ((char_u **)ga.ga_data)[ga.ga_len] = s;
6559 ++ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560 }
6561 }
6562 }
6563
6564 /*
6565 * Go over all the files and extract the tags.
6566 */
6567 for (fi = 0; fi < filecount && !got_int; ++fi)
6568 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00006569 fd = mch_fopen((char *)files[fi], "r");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006570 if (fd == NULL)
6571 {
6572 EMSG2(_("E153: Unable to open %s for reading"), files[fi]);
6573 continue;
6574 }
Bram Moolenaar442b5c42012-11-28 16:06:22 +01006575 fname = files[fi] + dirlen + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576
6577# ifdef FEAT_MBYTE
6578 firstline = TRUE;
6579# endif
6580 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
6581 {
6582# ifdef FEAT_MBYTE
6583 if (firstline)
6584 {
6585 /* Detect utf-8 file by a non-ASCII char in the first line. */
6586 this_utf8 = MAYBE;
6587 for (s = IObuff; *s != NUL; ++s)
6588 if (*s >= 0x80)
6589 {
6590 int l;
6591
6592 this_utf8 = TRUE;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006593 l = utf_ptr2len(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006594 if (l == 1)
6595 {
6596 /* Illegal UTF-8 byte sequence. */
6597 this_utf8 = FALSE;
6598 break;
6599 }
6600 s += l - 1;
6601 }
6602 if (this_utf8 == MAYBE) /* only ASCII characters found */
6603 this_utf8 = FALSE;
6604 if (utf8 == MAYBE) /* first file */
6605 utf8 = this_utf8;
6606 else if (utf8 != this_utf8)
6607 {
6608 EMSG2(_("E670: Mix of help file encodings within a language: %s"), files[fi]);
6609 mix = !got_int;
6610 got_int = TRUE;
6611 }
6612 firstline = FALSE;
6613 }
6614# endif
6615 p1 = vim_strchr(IObuff, '*'); /* find first '*' */
6616 while (p1 != NULL)
6617 {
Bram Moolenaara0149c72012-05-18 16:24:11 +02006618 /* Use vim_strbyte() instead of vim_strchr() so that when
6619 * 'encoding' is dbcs it still works, don't find '*' in the
6620 * second byte. */
6621 p2 = vim_strbyte(p1 + 1, '*'); /* find second '*' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006622 if (p2 != NULL && p2 > p1 + 1) /* skip "*" and "**" */
6623 {
6624 for (s = p1 + 1; s < p2; ++s)
6625 if (*s == ' ' || *s == '\t' || *s == '|')
6626 break;
6627
6628 /*
6629 * Only accept a *tag* when it consists of valid
6630 * characters, there is white space before it and is
6631 * followed by a white character or end-of-line.
6632 */
6633 if (s == p2
6634 && (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t')
6635 && (vim_strchr((char_u *)" \t\n\r", s[1]) != NULL
6636 || s[1] == '\0'))
6637 {
6638 *p2 = '\0';
6639 ++p1;
6640 if (ga_grow(&ga, 1) == FAIL)
6641 {
6642 got_int = TRUE;
6643 break;
6644 }
6645 s = alloc((unsigned)(p2 - p1 + STRLEN(fname) + 2));
6646 if (s == NULL)
6647 {
6648 got_int = TRUE;
6649 break;
6650 }
6651 ((char_u **)ga.ga_data)[ga.ga_len] = s;
6652 ++ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006653 sprintf((char *)s, "%s\t%s", p1, fname);
6654
6655 /* find next '*' */
6656 p2 = vim_strchr(p2 + 1, '*');
6657 }
6658 }
6659 p1 = p2;
6660 }
6661 line_breakcheck();
6662 }
6663
6664 fclose(fd);
6665 }
6666
6667 FreeWild(filecount, files);
6668
6669 if (!got_int)
6670 {
6671 /*
6672 * Sort the tags.
6673 */
6674 sort_strings((char_u **)ga.ga_data, ga.ga_len);
6675
6676 /*
6677 * Check for duplicates.
6678 */
6679 for (i = 1; i < ga.ga_len; ++i)
6680 {
6681 p1 = ((char_u **)ga.ga_data)[i - 1];
6682 p2 = ((char_u **)ga.ga_data)[i];
6683 while (*p1 == *p2)
6684 {
6685 if (*p2 == '\t')
6686 {
6687 *p2 = NUL;
Bram Moolenaar555b2802005-05-19 21:08:39 +00006688 vim_snprintf((char *)NameBuff, MAXPATHL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00006689 _("E154: Duplicate tag \"%s\" in file %s/%s"),
6690 ((char_u **)ga.ga_data)[i], dir, p2 + 1);
6691 EMSG(NameBuff);
6692 *p2 = '\t';
6693 break;
6694 }
6695 ++p1;
6696 ++p2;
6697 }
6698 }
6699
6700# ifdef FEAT_MBYTE
6701 if (utf8 == TRUE)
6702 fprintf(fd_tags, "!_TAG_FILE_ENCODING\tutf-8\t//\n");
6703# endif
6704
6705 /*
6706 * Write the tags into the file.
6707 */
6708 for (i = 0; i < ga.ga_len; ++i)
6709 {
6710 s = ((char_u **)ga.ga_data)[i];
Bram Moolenaarf6210482007-07-25 20:56:39 +00006711 if (STRNCMP(s, "help-tags\t", 10) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006712 /* help-tags entry was added in formatted form */
Bram Moolenaarf6210482007-07-25 20:56:39 +00006713 fputs((char *)s, fd_tags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006714 else
6715 {
6716 fprintf(fd_tags, "%s\t/*", s);
6717 for (p1 = s; *p1 != '\t'; ++p1)
6718 {
6719 /* insert backslash before '\\' and '/' */
6720 if (*p1 == '\\' || *p1 == '/')
6721 putc('\\', fd_tags);
6722 putc(*p1, fd_tags);
6723 }
6724 fprintf(fd_tags, "*\n");
6725 }
6726 }
6727 }
6728#ifdef FEAT_MBYTE
6729 if (mix)
6730 got_int = FALSE; /* continue with other languages */
6731#endif
6732
6733 for (i = 0; i < ga.ga_len; ++i)
6734 vim_free(((char_u **)ga.ga_data)[i]);
6735 ga_clear(&ga);
6736 fclose(fd_tags); /* there is no check for an error... */
6737}
6738#endif
6739
6740#if defined(FEAT_SIGNS) || defined(PROTO)
6741
6742/*
6743 * Struct to hold the sign properties.
6744 */
6745typedef struct sign sign_T;
6746
6747struct sign
6748{
6749 sign_T *sn_next; /* next sign in list */
Bram Moolenaarf75d4982010-10-15 20:20:05 +02006750 int sn_typenr; /* type number of sign */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006751 char_u *sn_name; /* name of sign */
6752 char_u *sn_icon; /* name of pixmap */
6753#ifdef FEAT_SIGN_ICONS
6754 void *sn_image; /* icon image */
6755#endif
6756 char_u *sn_text; /* text used instead of pixmap */
6757 int sn_line_hl; /* highlight ID for line */
6758 int sn_text_hl; /* highlight ID for text */
6759};
6760
Bram Moolenaar071d4272004-06-13 20:20:40 +00006761static sign_T *first_sign = NULL;
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006762static int next_sign_typenr = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006763
Bram Moolenaar985cb442009-05-14 19:51:46 +00006764static int sign_cmd_idx __ARGS((char_u *begin_cmd, char_u *end_cmd));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006765static void sign_list_defined __ARGS((sign_T *sp));
Bram Moolenaarde0dfed2009-02-24 03:30:14 +00006766static void sign_undefine __ARGS((sign_T *sp, sign_T *sp_prev));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006767
Bram Moolenaar3c65e312009-04-29 16:47:23 +00006768static char *cmds[] = {
6769 "define",
6770#define SIGNCMD_DEFINE 0
6771 "undefine",
6772#define SIGNCMD_UNDEFINE 1
6773 "list",
6774#define SIGNCMD_LIST 2
6775 "place",
6776#define SIGNCMD_PLACE 3
6777 "unplace",
6778#define SIGNCMD_UNPLACE 4
6779 "jump",
6780#define SIGNCMD_JUMP 5
6781 NULL
6782#define SIGNCMD_LAST 6
6783};
6784
6785/*
6786 * Find index of a ":sign" subcmd from its name.
6787 * "*end_cmd" must be writable.
6788 */
6789 static int
6790sign_cmd_idx(begin_cmd, end_cmd)
Bram Moolenaar985cb442009-05-14 19:51:46 +00006791 char_u *begin_cmd; /* begin of sign subcmd */
6792 char_u *end_cmd; /* just after sign subcmd */
Bram Moolenaar3c65e312009-04-29 16:47:23 +00006793{
6794 int idx;
6795 char save = *end_cmd;
6796
6797 *end_cmd = NUL;
6798 for (idx = 0; ; ++idx)
6799 if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0)
6800 break;
6801 *end_cmd = save;
6802 return idx;
6803}
6804
Bram Moolenaar071d4272004-06-13 20:20:40 +00006805/*
6806 * ":sign" command
6807 */
6808 void
6809ex_sign(eap)
6810 exarg_T *eap;
6811{
6812 char_u *arg = eap->arg;
6813 char_u *p;
6814 int idx;
6815 sign_T *sp;
6816 sign_T *sp_prev;
6817 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006818
6819 /* Parse the subcommand. */
6820 p = skiptowhite(arg);
Bram Moolenaar3c65e312009-04-29 16:47:23 +00006821 idx = sign_cmd_idx(arg, p);
6822 if (idx == SIGNCMD_LAST)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 {
Bram Moolenaar3c65e312009-04-29 16:47:23 +00006824 EMSG2(_("E160: Unknown sign command: %s"), arg);
6825 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006826 }
6827 arg = skipwhite(p);
6828
6829 if (idx <= SIGNCMD_LIST)
6830 {
6831 /*
6832 * Define, undefine or list signs.
6833 */
6834 if (idx == SIGNCMD_LIST && *arg == NUL)
6835 {
6836 /* ":sign list": list all defined signs */
Bram Moolenaar1c0b03e2012-03-16 14:32:15 +01006837 for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006838 sign_list_defined(sp);
6839 }
6840 else if (*arg == NUL)
6841 EMSG(_("E156: Missing sign name"));
6842 else
6843 {
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006844 /* Isolate the sign name. If it's a number skip leading zeroes,
6845 * so that "099" and "99" are the same sign. But keep "0". */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006846 p = skiptowhite(arg);
6847 if (*p != NUL)
6848 *p++ = NUL;
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006849 while (arg[0] == '0' && arg[1] != NUL)
6850 ++arg;
6851
Bram Moolenaar071d4272004-06-13 20:20:40 +00006852 sp_prev = NULL;
6853 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
6854 {
6855 if (STRCMP(sp->sn_name, arg) == 0)
6856 break;
6857 sp_prev = sp;
6858 }
6859 if (idx == SIGNCMD_DEFINE)
6860 {
6861 /* ":sign define {name} ...": define a sign */
6862 if (sp == NULL)
6863 {
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006864 sign_T *lp;
6865 int start = next_sign_typenr;
6866
Bram Moolenaar071d4272004-06-13 20:20:40 +00006867 /* Allocate a new sign. */
6868 sp = (sign_T *)alloc_clear((unsigned)sizeof(sign_T));
6869 if (sp == NULL)
6870 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006871
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006872 /* Check that next_sign_typenr is not already being used.
6873 * This only happens after wrapping around. Hopefully
6874 * another one got deleted and we can use its number. */
6875 for (lp = first_sign; lp != NULL; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006876 {
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006877 if (lp->sn_typenr == next_sign_typenr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006878 {
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006879 ++next_sign_typenr;
6880 if (next_sign_typenr == MAX_TYPENR)
6881 next_sign_typenr = 1;
6882 if (next_sign_typenr == start)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006883 {
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006884 vim_free(sp);
6885 EMSG(_("E612: Too many signs defined"));
6886 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006887 }
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006888 lp = first_sign; /* start all over */
6889 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006890 }
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006891 lp = lp->sn_next;
6892 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006893
Bram Moolenaarb60574b2010-10-14 21:29:37 +02006894 sp->sn_typenr = next_sign_typenr;
6895 if (++next_sign_typenr == MAX_TYPENR)
6896 next_sign_typenr = 1; /* wrap around */
6897
6898 sp->sn_name = vim_strsave(arg);
6899 if (sp->sn_name == NULL) /* out of memory */
6900 {
6901 vim_free(sp);
6902 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006903 }
Bram Moolenaara4f332b2010-10-13 16:44:23 +02006904
6905 /* add the new sign to the list of signs */
6906 if (sp_prev == NULL)
6907 first_sign = sp;
6908 else
6909 sp_prev->sn_next = sp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006910 }
6911
6912 /* set values for a defined sign. */
6913 for (;;)
6914 {
6915 arg = skipwhite(p);
6916 if (*arg == NUL)
6917 break;
6918 p = skiptowhite_esc(arg);
6919 if (STRNCMP(arg, "icon=", 5) == 0)
6920 {
6921 arg += 5;
6922 vim_free(sp->sn_icon);
6923 sp->sn_icon = vim_strnsave(arg, (int)(p - arg));
6924 backslash_halve(sp->sn_icon);
6925#ifdef FEAT_SIGN_ICONS
6926 if (gui.in_use)
6927 {
6928 out_flush();
6929 if (sp->sn_image != NULL)
6930 gui_mch_destroy_sign(sp->sn_image);
6931 sp->sn_image = gui_mch_register_sign(sp->sn_icon);
6932 }
6933#endif
6934 }
6935 else if (STRNCMP(arg, "text=", 5) == 0)
6936 {
6937 char_u *s;
6938 int cells;
6939 int len;
6940
6941 arg += 5;
6942#ifdef FEAT_MBYTE
6943 /* Count cells and check for non-printable chars */
6944 if (has_mbyte)
6945 {
6946 cells = 0;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006947 for (s = arg; s < p; s += (*mb_ptr2len)(s))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006948 {
6949 if (!vim_isprintc((*mb_ptr2char)(s)))
6950 break;
6951 cells += (*mb_ptr2cells)(s);
6952 }
6953 }
6954 else
6955#endif
6956 {
6957 for (s = arg; s < p; ++s)
6958 if (!vim_isprintc(*s))
6959 break;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006960 cells = (int)(s - arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 }
6962 /* Currently must be one or two display cells */
6963 if (s != p || cells < 1 || cells > 2)
6964 {
6965 *p = NUL;
6966 EMSG2(_("E239: Invalid sign text: %s"), arg);
6967 return;
6968 }
6969
6970 vim_free(sp->sn_text);
6971 /* Allocate one byte more if we need to pad up
6972 * with a space. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00006973 len = (int)(p - arg + ((cells == 1) ? 1 : 0));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006974 sp->sn_text = vim_strnsave(arg, len);
6975
6976 if (sp->sn_text != NULL && cells == 1)
6977 STRCPY(sp->sn_text + len - 1, " ");
6978 }
6979 else if (STRNCMP(arg, "linehl=", 7) == 0)
6980 {
6981 arg += 7;
6982 sp->sn_line_hl = syn_check_group(arg, (int)(p - arg));
6983 }
6984 else if (STRNCMP(arg, "texthl=", 7) == 0)
6985 {
6986 arg += 7;
6987 sp->sn_text_hl = syn_check_group(arg, (int)(p - arg));
6988 }
6989 else
6990 {
6991 EMSG2(_(e_invarg2), arg);
6992 return;
6993 }
6994 }
6995 }
6996 else if (sp == NULL)
6997 EMSG2(_("E155: Unknown sign: %s"), arg);
6998 else if (idx == SIGNCMD_LIST)
6999 /* ":sign list {name}" */
7000 sign_list_defined(sp);
7001 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007002 /* ":sign undefine {name}" */
Bram Moolenaarde0dfed2009-02-24 03:30:14 +00007003 sign_undefine(sp, sp_prev);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007004 }
7005 }
7006 else
7007 {
7008 int id = -1;
7009 linenr_T lnum = -1;
7010 char_u *sign_name = NULL;
7011 char_u *arg1;
7012
7013 if (*arg == NUL)
7014 {
7015 if (idx == SIGNCMD_PLACE)
7016 {
7017 /* ":sign place": list placed signs in all buffers */
7018 sign_list_placed(NULL);
7019 }
7020 else if (idx == SIGNCMD_UNPLACE)
7021 {
7022 /* ":sign unplace": remove placed sign at cursor */
7023 id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum);
7024 if (id > 0)
7025 {
7026 buf_delsign(curwin->w_buffer, id);
7027 update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum);
7028 }
7029 else
7030 EMSG(_("E159: Missing sign number"));
7031 }
7032 else
7033 EMSG(_(e_argreq));
7034 return;
7035 }
7036
7037 if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL)
7038 {
7039 /* ":sign unplace *": remove all placed signs */
7040 buf_delete_all_signs();
7041 return;
7042 }
7043
7044 /* first arg could be placed sign id */
7045 arg1 = arg;
7046 if (VIM_ISDIGIT(*arg))
7047 {
7048 id = getdigits(&arg);
7049 if (!vim_iswhite(*arg) && *arg != NUL)
7050 {
7051 id = -1;
7052 arg = arg1;
7053 }
7054 else
7055 {
7056 arg = skipwhite(arg);
7057 if (idx == SIGNCMD_UNPLACE && *arg == NUL)
7058 {
7059 /* ":sign unplace {id}": remove placed sign by number */
7060 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
7061 if ((lnum = buf_delsign(buf, id)) != 0)
7062 update_debug_sign(buf, lnum);
7063 return;
7064 }
7065 }
7066 }
7067
7068 /*
7069 * Check for line={lnum} name={name} and file={fname} or buffer={nr}.
7070 * Leave "arg" pointing to {fname}.
7071 */
7072 for (;;)
7073 {
7074 if (STRNCMP(arg, "line=", 5) == 0)
7075 {
7076 arg += 5;
7077 lnum = atoi((char *)arg);
7078 arg = skiptowhite(arg);
7079 }
Bram Moolenaarf65e5662012-07-10 15:18:22 +02007080 else if (STRNCMP(arg, "*", 1) == 0 && idx == SIGNCMD_UNPLACE)
7081 {
7082 if (id != -1)
7083 {
7084 EMSG(_(e_invarg));
7085 return;
7086 }
7087 id = -2;
7088 arg = skiptowhite(arg + 1);
7089 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007090 else if (STRNCMP(arg, "name=", 5) == 0)
7091 {
7092 arg += 5;
7093 sign_name = arg;
7094 arg = skiptowhite(arg);
7095 if (*arg != NUL)
7096 *arg++ = NUL;
Bram Moolenaarb60574b2010-10-14 21:29:37 +02007097 while (sign_name[0] == '0' && sign_name[1] != NUL)
7098 ++sign_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007099 }
7100 else if (STRNCMP(arg, "file=", 5) == 0)
7101 {
7102 arg += 5;
7103 buf = buflist_findname(arg);
7104 break;
7105 }
7106 else if (STRNCMP(arg, "buffer=", 7) == 0)
7107 {
7108 arg += 7;
7109 buf = buflist_findnr((int)getdigits(&arg));
7110 if (*skipwhite(arg) != NUL)
7111 EMSG(_(e_trailing));
7112 break;
7113 }
7114 else
7115 {
7116 EMSG(_(e_invarg));
7117 return;
7118 }
7119 arg = skipwhite(arg);
7120 }
7121
7122 if (buf == NULL)
7123 {
7124 EMSG2(_("E158: Invalid buffer name: %s"), arg);
7125 }
Bram Moolenaarf65e5662012-07-10 15:18:22 +02007126 else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007127 {
7128 if (lnum >= 0 || sign_name != NULL)
7129 EMSG(_(e_invarg));
7130 else
7131 /* ":sign place file={fname}": list placed signs in one file */
7132 sign_list_placed(buf);
7133 }
7134 else if (idx == SIGNCMD_JUMP)
7135 {
7136 /* ":sign jump {id} file={fname}" */
7137 if (lnum >= 0 || sign_name != NULL)
7138 EMSG(_(e_invarg));
7139 else if ((lnum = buf_findsign(buf, id)) > 0)
7140 { /* goto a sign ... */
7141 if (buf_jump_open_win(buf) != NULL)
7142 { /* ... in a current window */
7143 curwin->w_cursor.lnum = lnum;
7144 check_cursor_lnum();
7145 beginline(BL_WHITE);
7146 }
7147 else
7148 { /* ... not currently in a window */
7149 char_u *cmd;
7150
7151 cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25);
7152 if (cmd == NULL)
7153 return;
7154 sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname);
7155 do_cmdline_cmd(cmd);
7156 vim_free(cmd);
7157 }
7158#ifdef FEAT_FOLDING
7159 foldOpenCursor();
7160#endif
7161 }
7162 else
7163 EMSGN(_("E157: Invalid sign ID: %ld"), id);
7164 }
7165 else if (idx == SIGNCMD_UNPLACE)
7166 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007167 if (lnum >= 0 || sign_name != NULL)
7168 EMSG(_(e_invarg));
Bram Moolenaarf65e5662012-07-10 15:18:22 +02007169 else if (id == -2)
7170 {
7171 /* ":sign unplace * file={fname}" */
7172 redraw_buf_later(buf, NOT_VALID);
7173 buf_delete_signs(buf);
7174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007175 else
7176 {
Bram Moolenaarf65e5662012-07-10 15:18:22 +02007177 /* ":sign unplace {id} file={fname}" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007178 lnum = buf_delsign(buf, id);
7179 update_debug_sign(buf, lnum);
7180 }
7181 }
7182 /* idx == SIGNCMD_PLACE */
7183 else if (sign_name != NULL)
7184 {
7185 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7186 if (STRCMP(sp->sn_name, sign_name) == 0)
7187 break;
7188 if (sp == NULL)
7189 {
7190 EMSG2(_("E155: Unknown sign: %s"), sign_name);
7191 return;
7192 }
7193 if (lnum > 0)
7194 /* ":sign place {id} line={lnum} name={name} file={fname}":
7195 * place a sign */
7196 buf_addsign(buf, id, lnum, sp->sn_typenr);
7197 else
7198 /* ":sign place {id} file={fname}": change sign type */
7199 lnum = buf_change_sign_type(buf, id, sp->sn_typenr);
7200 update_debug_sign(buf, lnum);
7201 }
7202 else
7203 EMSG(_(e_invarg));
7204 }
7205}
7206
7207#if defined(FEAT_SIGN_ICONS) || defined(PROTO)
7208/*
7209 * Allocate the icons. Called when the GUI has started. Allows defining
7210 * signs before it starts.
7211 */
7212 void
7213sign_gui_started()
7214{
7215 sign_T *sp;
7216
7217 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7218 if (sp->sn_icon != NULL)
7219 sp->sn_image = gui_mch_register_sign(sp->sn_icon);
7220}
7221#endif
7222
7223/*
7224 * List one sign.
7225 */
7226 static void
7227sign_list_defined(sp)
7228 sign_T *sp;
7229{
7230 char_u *p;
7231
Bram Moolenaar555b2802005-05-19 21:08:39 +00007232 smsg((char_u *)"sign %s", sp->sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007233 if (sp->sn_icon != NULL)
7234 {
7235 MSG_PUTS(" icon=");
7236 msg_outtrans(sp->sn_icon);
7237#ifdef FEAT_SIGN_ICONS
7238 if (sp->sn_image == NULL)
7239 MSG_PUTS(_(" (NOT FOUND)"));
7240#else
7241 MSG_PUTS(_(" (not supported)"));
7242#endif
7243 }
7244 if (sp->sn_text != NULL)
7245 {
7246 MSG_PUTS(" text=");
7247 msg_outtrans(sp->sn_text);
7248 }
7249 if (sp->sn_line_hl > 0)
7250 {
7251 MSG_PUTS(" linehl=");
7252 p = get_highlight_name(NULL, sp->sn_line_hl - 1);
7253 if (p == NULL)
7254 MSG_PUTS("NONE");
7255 else
7256 msg_puts(p);
7257 }
7258 if (sp->sn_text_hl > 0)
7259 {
7260 MSG_PUTS(" texthl=");
7261 p = get_highlight_name(NULL, sp->sn_text_hl - 1);
7262 if (p == NULL)
7263 MSG_PUTS("NONE");
7264 else
7265 msg_puts(p);
7266 }
7267}
7268
7269/*
Bram Moolenaarde0dfed2009-02-24 03:30:14 +00007270 * Undefine a sign and free its memory.
7271 */
7272 static void
7273sign_undefine(sp, sp_prev)
7274 sign_T *sp;
7275 sign_T *sp_prev;
7276{
7277 vim_free(sp->sn_name);
7278 vim_free(sp->sn_icon);
7279#ifdef FEAT_SIGN_ICONS
7280 if (sp->sn_image != NULL)
7281 {
7282 out_flush();
7283 gui_mch_destroy_sign(sp->sn_image);
7284 }
7285#endif
7286 vim_free(sp->sn_text);
7287 if (sp_prev == NULL)
7288 first_sign = sp->sn_next;
7289 else
7290 sp_prev->sn_next = sp->sn_next;
7291 vim_free(sp);
7292}
7293
7294/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007295 * Get highlighting attribute for sign "typenr".
7296 * If "line" is TRUE: line highl, if FALSE: text highl.
7297 */
7298 int
7299sign_get_attr(typenr, line)
7300 int typenr;
7301 int line;
7302{
7303 sign_T *sp;
7304
7305 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7306 if (sp->sn_typenr == typenr)
7307 {
7308 if (line)
7309 {
7310 if (sp->sn_line_hl > 0)
7311 return syn_id2attr(sp->sn_line_hl);
7312 }
7313 else
7314 {
7315 if (sp->sn_text_hl > 0)
7316 return syn_id2attr(sp->sn_text_hl);
7317 }
7318 break;
7319 }
7320 return 0;
7321}
7322
7323/*
7324 * Get text mark for sign "typenr".
7325 * Returns NULL if there isn't one.
7326 */
7327 char_u *
7328sign_get_text(typenr)
7329 int typenr;
7330{
7331 sign_T *sp;
7332
7333 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7334 if (sp->sn_typenr == typenr)
7335 return sp->sn_text;
7336 return NULL;
7337}
7338
7339#if defined(FEAT_SIGN_ICONS) || defined(PROTO)
7340 void *
7341sign_get_image(typenr)
7342 int typenr; /* the attribute which may have a sign */
7343{
7344 sign_T *sp;
7345
7346 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7347 if (sp->sn_typenr == typenr)
7348 return sp->sn_image;
7349 return NULL;
7350}
7351#endif
7352
7353/*
7354 * Get the name of a sign by its typenr.
7355 */
7356 char_u *
7357sign_typenr2name(typenr)
7358 int typenr;
7359{
7360 sign_T *sp;
7361
7362 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7363 if (sp->sn_typenr == typenr)
7364 return sp->sn_name;
7365 return (char_u *)_("[Deleted]");
7366}
7367
Bram Moolenaarde0dfed2009-02-24 03:30:14 +00007368#if defined(EXITFREE) || defined(PROTO)
7369/*
7370 * Undefine/free all signs.
7371 */
7372 void
7373free_signs()
7374{
7375 while (first_sign != NULL)
7376 sign_undefine(first_sign, NULL);
7377}
7378#endif
7379
Bram Moolenaar3c65e312009-04-29 16:47:23 +00007380#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
7381static enum
7382{
7383 EXP_SUBCMD, /* expand :sign sub-commands */
7384 EXP_DEFINE, /* expand :sign define {name} args */
7385 EXP_PLACE, /* expand :sign place {id} args */
7386 EXP_UNPLACE, /* expand :sign unplace" */
7387 EXP_SIGN_NAMES /* expand with name of placed signs */
7388} expand_what;
7389
7390/*
7391 * Function given to ExpandGeneric() to obtain the sign command
7392 * expansion.
7393 */
Bram Moolenaar3c65e312009-04-29 16:47:23 +00007394 char_u *
7395get_sign_name(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00007396 expand_T *xp UNUSED;
Bram Moolenaar3c65e312009-04-29 16:47:23 +00007397 int idx;
7398{
7399 sign_T *sp;
7400 int current_idx;
7401
7402 switch (expand_what)
7403 {
7404 case EXP_SUBCMD:
7405 return (char_u *)cmds[idx];
7406 case EXP_DEFINE:
7407 {
7408 char *define_arg[] =
7409 {
7410 "icon=", "linehl=", "text=", "texthl=", NULL
7411 };
7412 return (char_u *)define_arg[idx];
7413 }
7414 case EXP_PLACE:
7415 {
7416 char *place_arg[] =
7417 {
7418 "line=", "name=", "file=", "buffer=", NULL
7419 };
7420 return (char_u *)place_arg[idx];
7421 }
7422 case EXP_UNPLACE:
7423 {
7424 char *unplace_arg[] = { "file=", "buffer=", NULL };
7425 return (char_u *)unplace_arg[idx];
7426 }
7427 case EXP_SIGN_NAMES:
7428 /* Complete with name of signs already defined */
7429 current_idx = 0;
7430 for (sp = first_sign; sp != NULL; sp = sp->sn_next)
7431 if (current_idx++ == idx)
7432 return sp->sn_name;
7433 return NULL;
7434 default:
7435 return NULL;
7436 }
7437}
7438
7439/*
7440 * Handle command line completion for :sign command.
7441 */
7442 void
7443set_context_in_sign_cmd(xp, arg)
7444 expand_T *xp;
7445 char_u *arg;
7446{
7447 char_u *p;
7448 char_u *end_subcmd;
7449 char_u *last;
7450 int cmd_idx;
7451 char_u *begin_subcmd_args;
7452
7453 /* Default: expand subcommands. */
7454 xp->xp_context = EXPAND_SIGN;
7455 expand_what = EXP_SUBCMD;
7456 xp->xp_pattern = arg;
7457
7458 end_subcmd = skiptowhite(arg);
7459 if (*end_subcmd == NUL)
7460 /* expand subcmd name
7461 * :sign {subcmd}<CTRL-D>*/
7462 return;
7463
7464 cmd_idx = sign_cmd_idx(arg, end_subcmd);
7465
7466 /* :sign {subcmd} {subcmd_args}
Bram Moolenaarcc448b32010-07-14 16:52:17 +02007467 * |
7468 * begin_subcmd_args */
Bram Moolenaar3c65e312009-04-29 16:47:23 +00007469 begin_subcmd_args = skipwhite(end_subcmd);
7470 p = skiptowhite(begin_subcmd_args);
7471 if (*p == NUL)
7472 {
7473 /*
7474 * Expand first argument of subcmd when possible.
7475 * For ":jump {id}" and ":unplace {id}", we could
7476 * possibly expand the ids of all signs already placed.
7477 */
7478 xp->xp_pattern = begin_subcmd_args;
7479 switch (cmd_idx)
7480 {
7481 case SIGNCMD_LIST:
7482 case SIGNCMD_UNDEFINE:
7483 /* :sign list <CTRL-D>
7484 * :sign undefine <CTRL-D> */
7485 expand_what = EXP_SIGN_NAMES;
7486 break;
7487 default:
7488 xp->xp_context = EXPAND_NOTHING;
7489 }
7490 return;
7491 }
7492
7493 /* expand last argument of subcmd */
7494
7495 /* :sign define {name} {args}...
Bram Moolenaarcc448b32010-07-14 16:52:17 +02007496 * |
7497 * p */
Bram Moolenaar3c65e312009-04-29 16:47:23 +00007498
7499 /* Loop until reaching last argument. */
7500 do
7501 {
7502 p = skipwhite(p);
7503 last = p;
7504 p = skiptowhite(p);
7505 } while (*p != NUL);
7506
7507 p = vim_strchr(last, '=');
7508
7509 /* :sign define {name} {args}... {last}=
Bram Moolenaarcc448b32010-07-14 16:52:17 +02007510 * | |
7511 * last p */
Bram Moolenaar3c65e312009-04-29 16:47:23 +00007512 if (p == NUL)
7513 {
7514 /* Expand last argument name (before equal sign). */
7515 xp->xp_pattern = last;
7516 switch (cmd_idx)
7517 {
7518 case SIGNCMD_DEFINE:
7519 expand_what = EXP_DEFINE;
7520 break;
7521 case SIGNCMD_PLACE:
7522 expand_what = EXP_PLACE;
7523 break;
7524 case SIGNCMD_JUMP:
7525 case SIGNCMD_UNPLACE:
7526 expand_what = EXP_UNPLACE;
7527 break;
7528 default:
7529 xp->xp_context = EXPAND_NOTHING;
7530 }
7531 }
7532 else
7533 {
7534 /* Expand last argument value (after equal sign). */
7535 xp->xp_pattern = p + 1;
7536 switch (cmd_idx)
7537 {
7538 case SIGNCMD_DEFINE:
7539 if (STRNCMP(last, "texthl", p - last) == 0 ||
7540 STRNCMP(last, "linehl", p - last) == 0)
7541 xp->xp_context = EXPAND_HIGHLIGHT;
7542 else if (STRNCMP(last, "icon", p - last) == 0)
7543 xp->xp_context = EXPAND_FILES;
7544 else
7545 xp->xp_context = EXPAND_NOTHING;
7546 break;
7547 case SIGNCMD_PLACE:
7548 if (STRNCMP(last, "name", p - last) == 0)
7549 expand_what = EXP_SIGN_NAMES;
7550 else
7551 xp->xp_context = EXPAND_NOTHING;
7552 break;
7553 default:
7554 xp->xp_context = EXPAND_NOTHING;
7555 }
7556 }
7557}
7558#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007559#endif
7560
7561#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
7562/*
7563 * ":drop"
7564 * Opens the first argument in a window. When there are two or more arguments
7565 * the argument list is redefined.
7566 */
7567 void
7568ex_drop(eap)
7569 exarg_T *eap;
7570{
7571 int split = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007572 win_T *wp;
7573 buf_T *buf;
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007574# ifdef FEAT_WINDOWS
7575 tabpage_T *tp;
7576# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007577
7578 /*
7579 * Check if the first argument is already being edited in a window. If
7580 * so, jump to that window.
7581 * We would actually need to check all arguments, but that's complicated
7582 * and mostly only one file is dropped.
7583 * This also ignores wildcards, since it is very unlikely the user is
7584 * editing a file name with a wildcard character.
7585 */
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007586 set_arglist(eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007587
Bram Moolenaarb01a8b72007-02-13 02:47:22 +00007588 /*
7589 * Expanding wildcards may result in an empty argument list. E.g. when
7590 * editing "foo.pyc" and ".pyc" is in 'wildignore'. Assume that we
7591 * already did an error message for this.
7592 */
7593 if (ARGCOUNT == 0)
7594 return;
7595
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007596# ifdef FEAT_WINDOWS
7597 if (cmdmod.tab)
7598 {
7599 /* ":tab drop file ...": open a tab for each argument that isn't
7600 * edited in a window yet. It's like ":tab all" but without closing
7601 * windows or tabs. */
7602 ex_all(eap);
7603 }
7604 else
7605# endif
7606 {
7607 /* ":drop file ...": Edit the first argument. Jump to an existing
7608 * window if possible, edit in current window if the current buffer
7609 * can be abandoned, otherwise open a new window. */
7610 buf = buflist_findnr(ARGLIST[0].ae_fnum);
7611
7612 FOR_ALL_TAB_WINDOWS(tp, wp)
7613 {
7614 if (wp->w_buffer == buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007615 {
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007616# ifdef FEAT_WINDOWS
Bram Moolenaar779b74b2006-04-10 14:55:34 +00007617 goto_tabpage_win(tp, wp);
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007618# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007619 curwin->w_arg_idx = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007620 return;
7621 }
7622 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007623
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007624 /*
7625 * Check whether the current buffer is changed. If so, we will need
7626 * to split the current window or data could be lost.
7627 * Skip the check if the 'hidden' option is set, as in this case the
7628 * buffer won't be lost.
7629 */
7630 if (!P_HID(curbuf))
7631 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007632# ifdef FEAT_WINDOWS
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007633 ++emsg_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007634# endif
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007635 split = check_changed(curbuf, TRUE, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007636# ifdef FEAT_WINDOWS
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007637 --emsg_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007638# else
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007639 if (split)
7640 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007641# endif
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007642 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007643
Bram Moolenaara5b6ad12006-03-11 21:36:59 +00007644 /* Fake a ":sfirst" or ":first" command edit the first argument. */
7645 if (split)
7646 {
7647 eap->cmdidx = CMD_sfirst;
7648 eap->cmd[0] = 's';
7649 }
7650 else
7651 eap->cmdidx = CMD_first;
7652 ex_rewind(eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007653 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007654}
7655#endif