blob: 26b570bcb092dc0b72d7a3f4ced031a71d5fa4cf [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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 * misc1.c: functions that didn't seem to fit elsewhere
12 */
13
14#include "vim.h"
15#include "version.h"
16
Bram Moolenaar828c3d72018-06-19 18:58:07 +020017#if defined(FEAT_CMDL_COMPL) && defined(WIN3264)
18# include <lm.h>
19#endif
20
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +010021static char_u *vim_version_dir(char_u *vimdir);
22static char_u *remove_tail(char_u *p, char_u *pend, char_u *name);
Bram Moolenaar071d4272004-06-13 20:20:40 +000023
Bram Moolenaar24305862012-08-15 14:05:05 +020024/* All user names (for ~user completion as done by shell). */
25#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
26static garray_T ga_users;
27#endif
28
Bram Moolenaar071d4272004-06-13 20:20:40 +000029/*
30 * Count the size (in window cells) of the indent in the current line.
31 */
32 int
Bram Moolenaar9b578142016-01-30 19:39:49 +010033get_indent(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000034{
Bram Moolenaar04958cb2018-06-23 19:23:02 +020035#ifdef FEAT_VARTABS
36 return get_indent_str_vtab(ml_get_curline(), (int)curbuf->b_p_ts,
37 curbuf->b_p_vts_array, FALSE);
38#else
Bram Moolenaar597a4222014-06-25 14:39:50 +020039 return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts, FALSE);
Bram Moolenaar04958cb2018-06-23 19:23:02 +020040#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000041}
42
43/*
44 * Count the size (in window cells) of the indent in line "lnum".
45 */
46 int
Bram Moolenaar9b578142016-01-30 19:39:49 +010047get_indent_lnum(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +000048{
Bram Moolenaar04958cb2018-06-23 19:23:02 +020049#ifdef FEAT_VARTABS
50 return get_indent_str_vtab(ml_get(lnum), (int)curbuf->b_p_ts,
51 curbuf->b_p_vts_array, FALSE);
52#else
Bram Moolenaar597a4222014-06-25 14:39:50 +020053 return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts, FALSE);
Bram Moolenaar04958cb2018-06-23 19:23:02 +020054#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000055}
56
57#if defined(FEAT_FOLDING) || defined(PROTO)
58/*
59 * Count the size (in window cells) of the indent in line "lnum" of buffer
60 * "buf".
61 */
62 int
Bram Moolenaar9b578142016-01-30 19:39:49 +010063get_indent_buf(buf_T *buf, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +000064{
Bram Moolenaar04958cb2018-06-23 19:23:02 +020065#ifdef FEAT_VARTABS
66 return get_indent_str_vtab(ml_get_buf(buf, lnum, FALSE),
67 (int)curbuf->b_p_ts, buf->b_p_vts_array, FALSE);
68#else
Bram Moolenaar597a4222014-06-25 14:39:50 +020069 return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts, FALSE);
Bram Moolenaar04958cb2018-06-23 19:23:02 +020070#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000071}
72#endif
73
74/*
75 * count the size (in window cells) of the indent in line "ptr", with
76 * 'tabstop' at "ts"
77 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +000078 int
Bram Moolenaar9b578142016-01-30 19:39:49 +010079get_indent_str(
80 char_u *ptr,
81 int ts,
82 int list) /* if TRUE, count only screen size for tabs */
Bram Moolenaar071d4272004-06-13 20:20:40 +000083{
84 int count = 0;
85
86 for ( ; *ptr; ++ptr)
87 {
Bram Moolenaar597a4222014-06-25 14:39:50 +020088 if (*ptr == TAB)
89 {
90 if (!list || lcs_tab1) /* count a tab for what it is worth */
91 count += ts - (count % ts);
92 else
Bram Moolenaare4df1642014-08-29 12:58:44 +020093 /* In list mode, when tab is not set, count screen char width
94 * for Tab, displays: ^I */
Bram Moolenaar597a4222014-06-25 14:39:50 +020095 count += ptr2cells(ptr);
96 }
Bram Moolenaar071d4272004-06-13 20:20:40 +000097 else if (*ptr == ' ')
98 ++count; /* count a space for one */
99 else
100 break;
101 }
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000102 return count;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000103}
104
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200105#ifdef FEAT_VARTABS
106/*
107 * Count the size (in window cells) of the indent in line "ptr", using
108 * variable tabstops.
109 * if "list" is TRUE, count only screen size for tabs.
110 */
111 int
112get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list)
113{
114 int count = 0;
115
116 for ( ; *ptr; ++ptr)
117 {
118 if (*ptr == TAB) /* count a tab for what it is worth */
119 {
120 if (!list || lcs_tab1)
121 count += tabstop_padding(count, ts, vts);
122 else
123 /* In list mode, when tab is not set, count screen char width
124 * for Tab, displays: ^I */
125 count += ptr2cells(ptr);
126 }
127 else if (*ptr == ' ')
128 ++count; /* count a space for one */
129 else
130 break;
131 }
132 return count;
133}
134#endif
135
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136/*
137 * Set the indent of the current line.
138 * Leaves the cursor on the first non-blank in the line.
139 * Caller must take care of undo.
140 * "flags":
141 * SIN_CHANGED: call changed_bytes() if the line was changed.
142 * SIN_INSERT: insert the indent in front of the line.
143 * SIN_UNDO: save line for undo before changing it.
144 * Returns TRUE if the line was changed.
145 */
146 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100147set_indent(
148 int size, /* measured in spaces */
149 int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150{
151 char_u *p;
152 char_u *newline;
153 char_u *oldline;
154 char_u *s;
155 int todo;
Bram Moolenaar5002c292007-07-24 13:26:15 +0000156 int ind_len; /* measured in characters */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 int line_len;
158 int doit = FALSE;
Bram Moolenaar5002c292007-07-24 13:26:15 +0000159 int ind_done = 0; /* measured in spaces */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200160#ifdef FEAT_VARTABS
161 int ind_col = 0;
162#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 int tab_pad;
Bram Moolenaar5409c052005-03-18 20:27:04 +0000164 int retval = FALSE;
Bram Moolenaar4d64b782007-08-14 20:16:42 +0000165 int orig_char_len = -1; /* number of initial whitespace chars when
Bram Moolenaar5002c292007-07-24 13:26:15 +0000166 'et' and 'pi' are both set */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167
168 /*
169 * First check if there is anything to do and compute the number of
170 * characters needed for the indent.
171 */
172 todo = size;
173 ind_len = 0;
174 p = oldline = ml_get_curline();
175
176 /* Calculate the buffer size for the new indent, and check to see if it
177 * isn't already set */
178
Bram Moolenaar5002c292007-07-24 13:26:15 +0000179 /* if 'expandtab' isn't set: use TABs; if both 'expandtab' and
180 * 'preserveindent' are set count the number of characters at the
181 * beginning of the line to be copied */
182 if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183 {
184 /* If 'preserveindent' is set then reuse as much as possible of
185 * the existing indent structure for the new indent */
186 if (!(flags & SIN_INSERT) && curbuf->b_p_pi)
187 {
188 ind_done = 0;
189
190 /* count as many characters as we can use */
Bram Moolenaar1c465442017-03-12 20:10:05 +0100191 while (todo > 0 && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192 {
193 if (*p == TAB)
194 {
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200195#ifdef FEAT_VARTABS
196 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
197 curbuf->b_p_vts_array);
198#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199 tab_pad = (int)curbuf->b_p_ts
200 - (ind_done % (int)curbuf->b_p_ts);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200201#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202 /* stop if this tab will overshoot the target */
203 if (todo < tab_pad)
204 break;
205 todo -= tab_pad;
206 ++ind_len;
207 ind_done += tab_pad;
208 }
209 else
210 {
211 --todo;
212 ++ind_len;
213 ++ind_done;
214 }
215 ++p;
216 }
217
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200218#ifdef FEAT_VARTABS
219 /* These diverge from this point. */
220 ind_col = ind_done;
221#endif
Bram Moolenaar5002c292007-07-24 13:26:15 +0000222 /* Set initial number of whitespace chars to copy if we are
223 * preserving indent but expandtab is set */
224 if (curbuf->b_p_et)
225 orig_char_len = ind_len;
226
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227 /* Fill to next tabstop with a tab, if possible */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200228#ifdef FEAT_VARTABS
229 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
230 curbuf->b_p_vts_array);
231#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200233#endif
Bram Moolenaar4d64b782007-08-14 20:16:42 +0000234 if (todo >= tab_pad && orig_char_len == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235 {
236 doit = TRUE;
237 todo -= tab_pad;
238 ++ind_len;
239 /* ind_done += tab_pad; */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200240#ifdef FEAT_VARTABS
241 ind_col += tab_pad;
242#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 }
244 }
245
246 /* count tabs required for indent */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200247#ifdef FEAT_VARTABS
248 for (;;)
249 {
250 tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts,
251 curbuf->b_p_vts_array);
252 if (todo < tab_pad)
253 break;
254 if (*p != TAB)
255 doit = TRUE;
256 else
257 ++p;
258 todo -= tab_pad;
259 ++ind_len;
260 ind_col += tab_pad;
261 }
262#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263 while (todo >= (int)curbuf->b_p_ts)
264 {
265 if (*p != TAB)
266 doit = TRUE;
267 else
268 ++p;
269 todo -= (int)curbuf->b_p_ts;
270 ++ind_len;
271 /* ind_done += (int)curbuf->b_p_ts; */
272 }
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200273#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274 }
275 /* count spaces required for indent */
276 while (todo > 0)
277 {
278 if (*p != ' ')
279 doit = TRUE;
280 else
281 ++p;
282 --todo;
283 ++ind_len;
284 /* ++ind_done; */
285 }
286
287 /* Return if the indent is OK already. */
Bram Moolenaar1c465442017-03-12 20:10:05 +0100288 if (!doit && !VIM_ISWHITE(*p) && !(flags & SIN_INSERT))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 return FALSE;
290
291 /* Allocate memory for the new line. */
292 if (flags & SIN_INSERT)
293 p = oldline;
294 else
295 p = skipwhite(p);
296 line_len = (int)STRLEN(p) + 1;
Bram Moolenaar5002c292007-07-24 13:26:15 +0000297
298 /* If 'preserveindent' and 'expandtab' are both set keep the original
299 * characters and allocate accordingly. We will fill the rest with spaces
300 * after the if (!curbuf->b_p_et) below. */
Bram Moolenaar4d64b782007-08-14 20:16:42 +0000301 if (orig_char_len != -1)
Bram Moolenaar5002c292007-07-24 13:26:15 +0000302 {
303 newline = alloc(orig_char_len + size - ind_done + line_len);
304 if (newline == NULL)
305 return FALSE;
Bram Moolenaar4d64b782007-08-14 20:16:42 +0000306 todo = size - ind_done;
307 ind_len = orig_char_len + todo; /* Set total length of indent in
308 * characters, which may have been
309 * undercounted until now */
Bram Moolenaar5002c292007-07-24 13:26:15 +0000310 p = oldline;
311 s = newline;
312 while (orig_char_len > 0)
313 {
314 *s++ = *p++;
315 orig_char_len--;
316 }
Bram Moolenaar913626c2008-01-03 11:43:42 +0000317
Bram Moolenaar5002c292007-07-24 13:26:15 +0000318 /* Skip over any additional white space (useful when newindent is less
319 * than old) */
Bram Moolenaar1c465442017-03-12 20:10:05 +0100320 while (VIM_ISWHITE(*p))
Bram Moolenaar913626c2008-01-03 11:43:42 +0000321 ++p;
Bram Moolenaarcc00b952007-08-11 12:32:57 +0000322
Bram Moolenaar5002c292007-07-24 13:26:15 +0000323 }
324 else
325 {
326 todo = size;
327 newline = alloc(ind_len + line_len);
328 if (newline == NULL)
329 return FALSE;
330 s = newline;
331 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000332
333 /* Put the characters in the new line. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000334 /* if 'expandtab' isn't set: use TABs */
335 if (!curbuf->b_p_et)
336 {
337 /* If 'preserveindent' is set then reuse as much as possible of
338 * the existing indent structure for the new indent */
339 if (!(flags & SIN_INSERT) && curbuf->b_p_pi)
340 {
341 p = oldline;
342 ind_done = 0;
343
Bram Moolenaar1c465442017-03-12 20:10:05 +0100344 while (todo > 0 && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000345 {
346 if (*p == TAB)
347 {
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200348#ifdef FEAT_VARTABS
349 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
350 curbuf->b_p_vts_array);
351#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 tab_pad = (int)curbuf->b_p_ts
353 - (ind_done % (int)curbuf->b_p_ts);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200354#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355 /* stop if this tab will overshoot the target */
356 if (todo < tab_pad)
357 break;
358 todo -= tab_pad;
359 ind_done += tab_pad;
360 }
361 else
362 {
363 --todo;
364 ++ind_done;
365 }
366 *s++ = *p++;
367 }
368
369 /* Fill to next tabstop with a tab, if possible */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200370#ifdef FEAT_VARTABS
371 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
372 curbuf->b_p_vts_array);
373#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200375#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376 if (todo >= tab_pad)
377 {
378 *s++ = TAB;
379 todo -= tab_pad;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200380#ifdef FEAT_VARTABS
381 ind_done += tab_pad;
382#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 }
384
385 p = skipwhite(p);
386 }
387
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200388#ifdef FEAT_VARTABS
389 for (;;)
390 {
391 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
392 curbuf->b_p_vts_array);
393 if (todo < tab_pad)
394 break;
395 *s++ = TAB;
396 todo -= tab_pad;
397 ind_done += tab_pad;
398 }
399#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 while (todo >= (int)curbuf->b_p_ts)
401 {
402 *s++ = TAB;
403 todo -= (int)curbuf->b_p_ts;
404 }
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200405#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 }
407 while (todo > 0)
408 {
409 *s++ = ' ';
410 --todo;
411 }
412 mch_memmove(s, p, (size_t)line_len);
413
Bram Moolenaar663bc892019-01-08 23:07:24 +0100414 // Replace the line (unless undo fails).
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK)
416 {
417 ml_replace(curwin->w_cursor.lnum, newline, FALSE);
418 if (flags & SIN_CHANGED)
419 changed_bytes(curwin->w_cursor.lnum, 0);
Bram Moolenaar663bc892019-01-08 23:07:24 +0100420
421 // Correct saved cursor position if it is in this line.
Bram Moolenaar2c019c82013-10-06 17:46:56 +0200422 if (saved_cursor.lnum == curwin->w_cursor.lnum)
423 {
424 if (saved_cursor.col >= (colnr_T)(p - oldline))
Bram Moolenaar663bc892019-01-08 23:07:24 +0100425 // cursor was after the indent, adjust for the number of
426 // bytes added/removed
Bram Moolenaar2c019c82013-10-06 17:46:56 +0200427 saved_cursor.col += ind_len - (colnr_T)(p - oldline);
428 else if (saved_cursor.col >= (colnr_T)(s - newline))
Bram Moolenaar663bc892019-01-08 23:07:24 +0100429 // cursor was in the indent, and is now after it, put it back
430 // at the start of the indent (replacing spaces with TAB)
Bram Moolenaar2c019c82013-10-06 17:46:56 +0200431 saved_cursor.col = (colnr_T)(s - newline);
432 }
Bram Moolenaar663bc892019-01-08 23:07:24 +0100433#ifdef FEAT_TEXT_PROP
434 adjust_prop_columns(curwin->w_cursor.lnum, (colnr_T)(p - oldline),
435 ind_len - (colnr_T)(p - oldline));
436#endif
Bram Moolenaar5409c052005-03-18 20:27:04 +0000437 retval = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 }
439 else
440 vim_free(newline);
441
442 curwin->w_cursor.col = ind_len;
Bram Moolenaar5409c052005-03-18 20:27:04 +0000443 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444}
445
446/*
447 * Copy the indent from ptr to the current line (and fill to size)
448 * Leaves the cursor on the first non-blank in the line.
449 * Returns TRUE if the line was changed.
450 */
451 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100452copy_indent(int size, char_u *src)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453{
454 char_u *p = NULL;
455 char_u *line = NULL;
456 char_u *s;
457 int todo;
458 int ind_len;
459 int line_len = 0;
460 int tab_pad;
461 int ind_done;
462 int round;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200463#ifdef FEAT_VARTABS
464 int ind_col;
465#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466
467 /* Round 1: compute the number of characters needed for the indent
468 * Round 2: copy the characters. */
469 for (round = 1; round <= 2; ++round)
470 {
471 todo = size;
472 ind_len = 0;
473 ind_done = 0;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200474#ifdef FEAT_VARTABS
475 ind_col = 0;
476#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 s = src;
478
479 /* Count/copy the usable portion of the source line */
Bram Moolenaar1c465442017-03-12 20:10:05 +0100480 while (todo > 0 && VIM_ISWHITE(*s))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481 {
482 if (*s == TAB)
483 {
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200484#ifdef FEAT_VARTABS
485 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
486 curbuf->b_p_vts_array);
487#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 tab_pad = (int)curbuf->b_p_ts
489 - (ind_done % (int)curbuf->b_p_ts);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200490#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 /* Stop if this tab will overshoot the target */
492 if (todo < tab_pad)
493 break;
494 todo -= tab_pad;
495 ind_done += tab_pad;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200496#ifdef FEAT_VARTABS
497 ind_col += tab_pad;
498#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000499 }
500 else
501 {
502 --todo;
503 ++ind_done;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200504#ifdef FEAT_VARTABS
505 ++ind_col;
506#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 }
508 ++ind_len;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000509 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 *p++ = *s;
511 ++s;
512 }
513
514 /* Fill to next tabstop with a tab, if possible */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200515#ifdef FEAT_VARTABS
516 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
517 curbuf->b_p_vts_array);
518#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200520#endif
Bram Moolenaarc42e7ed2011-09-07 19:58:09 +0200521 if (todo >= tab_pad && !curbuf->b_p_et)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 {
523 todo -= tab_pad;
524 ++ind_len;
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200525#ifdef FEAT_VARTABS
526 ind_col += tab_pad;
527#endif
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000528 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 *p++ = TAB;
530 }
531
532 /* Add tabs required for indent */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200533 if (!curbuf->b_p_et)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 {
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200535#ifdef FEAT_VARTABS
536 for (;;)
537 {
538 tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts,
539 curbuf->b_p_vts_array);
540 if (todo < tab_pad)
541 break;
542 todo -= tab_pad;
543 ++ind_len;
544 ind_col += tab_pad;
545 if (p != NULL)
546 *p++ = TAB;
547 }
548#else
549 while (todo >= (int)curbuf->b_p_ts)
550 {
551 todo -= (int)curbuf->b_p_ts;
552 ++ind_len;
553 if (p != NULL)
554 *p++ = TAB;
555 }
556#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 }
558
559 /* Count/add spaces required for indent */
560 while (todo > 0)
561 {
562 --todo;
563 ++ind_len;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000564 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 *p++ = ' ';
566 }
567
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000568 if (p == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569 {
570 /* Allocate memory for the result: the copied indent, new indent
571 * and the rest of the line. */
572 line_len = (int)STRLEN(ml_get_curline()) + 1;
573 line = alloc(ind_len + line_len);
574 if (line == NULL)
575 return FALSE;
576 p = line;
577 }
578 }
579
580 /* Append the original line */
581 mch_memmove(p, ml_get_curline(), (size_t)line_len);
582
583 /* Replace the line */
584 ml_replace(curwin->w_cursor.lnum, line, FALSE);
585
586 /* Put the cursor after the indent. */
587 curwin->w_cursor.col = ind_len;
588 return TRUE;
589}
590
591/*
592 * Return the indent of the current line after a number. Return -1 if no
593 * number was found. Used for 'n' in 'formatoptions': numbered list.
Bram Moolenaar86b68352004-12-27 21:59:20 +0000594 * Since a pattern is used it can actually handle more than numbers.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595 */
596 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100597get_number_indent(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000598{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599 colnr_T col;
600 pos_T pos;
601
Bram Moolenaar96b7ca52012-06-29 15:04:49 +0200602 regmatch_T regmatch;
603 int lead_len = 0; /* length of comment leader */
604
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 if (lnum > curbuf->b_ml.ml_line_count)
606 return -1;
Bram Moolenaar86b68352004-12-27 21:59:20 +0000607 pos.lnum = 0;
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200608
609#ifdef FEAT_COMMENTS
Bram Moolenaar96b7ca52012-06-29 15:04:49 +0200610 /* In format_lines() (i.e. not insert mode), fo+=q is needed too... */
611 if ((State & INSERT) || has_format_option(FO_Q_COMS))
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200612 lead_len = get_leader_len(ml_get(lnum), NULL, FALSE, TRUE);
Bram Moolenaar86b68352004-12-27 21:59:20 +0000613#endif
Bram Moolenaar96b7ca52012-06-29 15:04:49 +0200614 regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
615 if (regmatch.regprog != NULL)
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200616 {
Bram Moolenaar96b7ca52012-06-29 15:04:49 +0200617 regmatch.rm_ic = FALSE;
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200618
Bram Moolenaar96b7ca52012-06-29 15:04:49 +0200619 /* vim_regexec() expects a pointer to a line. This lets us
620 * start matching for the flp beyond any comment leader... */
621 if (vim_regexec(&regmatch, ml_get(lnum) + lead_len, (colnr_T)0))
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200622 {
Bram Moolenaar96b7ca52012-06-29 15:04:49 +0200623 pos.lnum = lnum;
624 pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum));
Bram Moolenaar96b7ca52012-06-29 15:04:49 +0200625 pos.coladd = 0;
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200626 }
Bram Moolenaar473de612013-06-08 18:19:48 +0200627 vim_regfree(regmatch.regprog);
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200628 }
Bram Moolenaar86b68352004-12-27 21:59:20 +0000629
630 if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 return -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 getvcol(curwin, &pos, &col, NULL, NULL);
633 return (int)col;
634}
635
Bram Moolenaar597a4222014-06-25 14:39:50 +0200636#if defined(FEAT_LINEBREAK) || defined(PROTO)
637/*
638 * Return appropriate space number for breakindent, taking influencing
639 * parameters into account. Window must be specified, since it is not
640 * necessarily always the current one.
641 */
642 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100643get_breakindent_win(
644 win_T *wp,
645 char_u *line) /* start of the line */
Bram Moolenaar597a4222014-06-25 14:39:50 +0200646{
647 static int prev_indent = 0; /* cached indent value */
648 static long prev_ts = 0L; /* cached tabstop value */
649 static char_u *prev_line = NULL; /* cached pointer to line */
Bram Moolenaar79518e22017-02-17 16:31:35 +0100650 static varnumber_T prev_tick = 0; /* changedtick of cached value */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200651#ifdef FEAT_VARTABS
652 static int *prev_vts = NULL; /* cached vartabs values */
653#endif
Bram Moolenaar597a4222014-06-25 14:39:50 +0200654 int bri = 0;
655 /* window width minus window margin space, i.e. what rests for text */
Bram Moolenaar02631462017-09-22 15:20:32 +0200656 const int eff_wwidth = wp->w_width
Bram Moolenaar597a4222014-06-25 14:39:50 +0200657 - ((wp->w_p_nu || wp->w_p_rnu)
658 && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
659 ? number_width(wp) + 1 : 0);
660
661 /* used cached indent, unless pointer or 'tabstop' changed */
Bram Moolenaara40aa762014-06-25 22:55:38 +0200662 if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200663 || prev_tick != CHANGEDTICK(wp->w_buffer)
664#ifdef FEAT_VARTABS
665 || prev_vts != wp->w_buffer->b_p_vts_array
666#endif
667 )
Bram Moolenaar597a4222014-06-25 14:39:50 +0200668 {
669 prev_line = line;
670 prev_ts = wp->w_buffer->b_p_ts;
Bram Moolenaar95c526e2017-02-25 14:59:34 +0100671 prev_tick = CHANGEDTICK(wp->w_buffer);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200672#ifdef FEAT_VARTABS
673 prev_vts = wp->w_buffer->b_p_vts_array;
674 prev_indent = get_indent_str_vtab(line,
675 (int)wp->w_buffer->b_p_ts,
676 wp->w_buffer->b_p_vts_array, wp->w_p_list);
677#else
Bram Moolenaar597a4222014-06-25 14:39:50 +0200678 prev_indent = get_indent_str(line,
Bram Moolenaar9d7a5922014-06-26 21:24:56 +0200679 (int)wp->w_buffer->b_p_ts, wp->w_p_list);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200680#endif
Bram Moolenaar597a4222014-06-25 14:39:50 +0200681 }
Bram Moolenaar9d7a5922014-06-26 21:24:56 +0200682 bri = prev_indent + wp->w_p_brishift;
Bram Moolenaar597a4222014-06-25 14:39:50 +0200683
684 /* indent minus the length of the showbreak string */
Bram Moolenaar597a4222014-06-25 14:39:50 +0200685 if (wp->w_p_brisbr)
686 bri -= vim_strsize(p_sbr);
687
688 /* Add offset for number column, if 'n' is in 'cpoptions' */
689 bri += win_col_off2(wp);
690
691 /* never indent past left window margin */
692 if (bri < 0)
693 bri = 0;
694 /* always leave at least bri_min characters on the left,
695 * if text width is sufficient */
696 else if (bri > eff_wwidth - wp->w_p_brimin)
697 bri = (eff_wwidth - wp->w_p_brimin < 0)
698 ? 0 : eff_wwidth - wp->w_p_brimin;
699
700 return bri;
701}
702#endif
703
704
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705/*
706 * open_line: Add a new line below or above the current line.
707 *
708 * For VREPLACE mode, we only add a new line when we get to the end of the
709 * file, otherwise we just start replacing the next line.
710 *
711 * Caller must take care of undo. Since VREPLACE may affect any number of
712 * lines however, it may call u_save_cursor() again when starting to change a
713 * new line.
714 * "flags": OPENLINE_DELSPACES delete spaces after cursor
715 * OPENLINE_DO_COM format comments
716 * OPENLINE_KEEPTRAIL keep trailing spaces
717 * OPENLINE_MARKFIX adjust mark positions after the line break
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200718 * OPENLINE_COM_LIST format comments with list or 2nd line indent
719 *
720 * "second_line_indent": indent for after ^^D in Insert mode or if flag
721 * OPENLINE_COM_LIST
Bram Moolenaar071d4272004-06-13 20:20:40 +0000722 *
Bram Moolenaar24a2d722018-04-24 19:36:43 +0200723 * Return OK for success, FAIL for failure
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724 */
725 int
Bram Moolenaar9b578142016-01-30 19:39:49 +0100726open_line(
727 int dir, /* FORWARD or BACKWARD */
728 int flags,
729 int second_line_indent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000730{
731 char_u *saved_line; /* copy of the original line */
732 char_u *next_line = NULL; /* copy of the next line */
733 char_u *p_extra = NULL; /* what goes to next line */
734 int less_cols = 0; /* less columns for mark in new line */
735 int less_cols_off = 0; /* columns to skip for mark adjust */
736 pos_T old_cursor; /* old cursor position */
737 int newcol = 0; /* new cursor column */
738 int newindent = 0; /* auto-indent of the new line */
739 int n;
740 int trunc_line = FALSE; /* truncate current line afterwards */
Bram Moolenaar24a2d722018-04-24 19:36:43 +0200741 int retval = FAIL; /* return value */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742#ifdef FEAT_COMMENTS
743 int extra_len = 0; /* length of p_extra string */
744 int lead_len; /* length of comment leader */
745 char_u *lead_flags; /* position in 'comments' for comment leader */
746 char_u *leader = NULL; /* copy of comment leader */
747#endif
748 char_u *allocated = NULL; /* allocated memory */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 int saved_char = NUL; /* init for GCC */
751#if defined(FEAT_SMARTINDENT) || defined(FEAT_COMMENTS)
752 pos_T *pos;
753#endif
754#ifdef FEAT_SMARTINDENT
755 int do_si = (!p_paste && curbuf->b_p_si
756# ifdef FEAT_CINDENT
757 && !curbuf->b_p_cin
758# endif
Bram Moolenaar69a76fe2017-08-03 17:54:03 +0200759# ifdef FEAT_EVAL
760 && *curbuf->b_p_inde == NUL
761# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762 );
763 int no_si = FALSE; /* reset did_si afterwards */
764 int first_char = NUL; /* init for GCC */
765#endif
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +0200766#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767 int vreplace_mode;
768#endif
769 int did_append; /* appended a new line */
770 int saved_pi = curbuf->b_p_pi; /* copy of preserveindent setting */
771
772 /*
773 * make a copy of the current line so we can mess with it
774 */
775 saved_line = vim_strsave(ml_get_curline());
776 if (saved_line == NULL) /* out of memory! */
777 return FALSE;
778
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 if (State & VREPLACE_FLAG)
780 {
781 /*
782 * With VREPLACE we make a copy of the next line, which we will be
783 * starting to replace. First make the new line empty and let vim play
784 * with the indenting and comment leader to its heart's content. Then
785 * we grab what it ended up putting on the new line, put back the
786 * original line, and call ins_char() to put each new character onto
787 * the line, replacing what was there before and pushing the right
788 * stuff onto the replace stack. -- webb.
789 */
790 if (curwin->w_cursor.lnum < orig_line_count)
791 next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1));
792 else
793 next_line = vim_strsave((char_u *)"");
794 if (next_line == NULL) /* out of memory! */
795 goto theend;
796
797 /*
798 * In VREPLACE mode, a NL replaces the rest of the line, and starts
799 * replacing the next line, so push all of the characters left on the
800 * line onto the replace stack. We'll push any other characters that
801 * might be replaced at the start of the next line (due to autoindent
802 * etc) a bit later.
803 */
804 replace_push(NUL); /* Call twice because BS over NL expects it */
805 replace_push(NUL);
806 p = saved_line + curwin->w_cursor.col;
807 while (*p != NUL)
Bram Moolenaar2c994e82008-01-02 16:49:36 +0000808 {
Bram Moolenaar2c994e82008-01-02 16:49:36 +0000809 if (has_mbyte)
810 p += replace_push_mb(p);
811 else
Bram Moolenaar2c994e82008-01-02 16:49:36 +0000812 replace_push(*p++);
813 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 saved_line[curwin->w_cursor.col] = NUL;
815 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +0200817 if ((State & INSERT) && !(State & VREPLACE_FLAG))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 {
819 p_extra = saved_line + curwin->w_cursor.col;
820#ifdef FEAT_SMARTINDENT
821 if (do_si) /* need first char after new line break */
822 {
823 p = skipwhite(p_extra);
824 first_char = *p;
825 }
826#endif
827#ifdef FEAT_COMMENTS
828 extra_len = (int)STRLEN(p_extra);
829#endif
830 saved_char = *p_extra;
831 *p_extra = NUL;
832 }
833
834 u_clearline(); /* cannot do "U" command when adding lines */
835#ifdef FEAT_SMARTINDENT
836 did_si = FALSE;
837#endif
838 ai_col = 0;
839
840 /*
841 * If we just did an auto-indent, then we didn't type anything on
842 * the prior line, and it should be truncated. Do this even if 'ai' is not
843 * set because automatically inserting a comment leader also sets did_ai.
844 */
845 if (dir == FORWARD && did_ai)
846 trunc_line = TRUE;
847
848 /*
849 * If 'autoindent' and/or 'smartindent' is set, try to figure out what
850 * indent to use for the new line.
851 */
852 if (curbuf->b_p_ai
853#ifdef FEAT_SMARTINDENT
854 || do_si
855#endif
856 )
857 {
858 /*
859 * count white space on current line
860 */
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200861#ifdef FEAT_VARTABS
862 newindent = get_indent_str_vtab(saved_line, curbuf->b_p_ts,
863 curbuf->b_p_vts_array, FALSE);
864#else
Bram Moolenaar597a4222014-06-25 14:39:50 +0200865 newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE);
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200866#endif
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +0200867 if (newindent == 0 && !(flags & OPENLINE_COM_LIST))
868 newindent = second_line_indent; /* for ^^D command in insert mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869
870#ifdef FEAT_SMARTINDENT
871 /*
872 * Do smart indenting.
873 * In insert/replace mode (only when dir == FORWARD)
874 * we may move some text to the next line. If it starts with '{'
875 * don't add an indent. Fixes inserting a NL before '{' in line
876 * "if (condition) {"
877 */
878 if (!trunc_line && do_si && *saved_line != NUL
879 && (p_extra == NULL || first_char != '{'))
880 {
881 char_u *ptr;
882 char_u last_char;
883
884 old_cursor = curwin->w_cursor;
885 ptr = saved_line;
886# ifdef FEAT_COMMENTS
887 if (flags & OPENLINE_DO_COM)
Bram Moolenaar81340392012-06-06 16:12:59 +0200888 lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 else
890 lead_len = 0;
891# endif
892 if (dir == FORWARD)
893 {
894 /*
895 * Skip preprocessor directives, unless they are
896 * recognised as comments.
897 */
898 if (
899# ifdef FEAT_COMMENTS
900 lead_len == 0 &&
901# endif
902 ptr[0] == '#')
903 {
904 while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
905 ptr = ml_get(--curwin->w_cursor.lnum);
906 newindent = get_indent();
907 }
908# ifdef FEAT_COMMENTS
909 if (flags & OPENLINE_DO_COM)
Bram Moolenaar81340392012-06-06 16:12:59 +0200910 lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911 else
912 lead_len = 0;
913 if (lead_len > 0)
914 {
915 /*
916 * This case gets the following right:
917 * \*
918 * * A comment (read '\' as '/').
919 * *\
920 * #define IN_THE_WAY
921 * This should line up here;
922 */
923 p = skipwhite(ptr);
924 if (p[0] == '/' && p[1] == '*')
925 p++;
926 if (p[0] == '*')
927 {
928 for (p++; *p; p++)
929 {
930 if (p[0] == '/' && p[-1] == '*')
931 {
932 /*
933 * End of C comment, indent should line up
934 * with the line containing the start of
935 * the comment
936 */
937 curwin->w_cursor.col = (colnr_T)(p - ptr);
938 if ((pos = findmatch(NULL, NUL)) != NULL)
939 {
940 curwin->w_cursor.lnum = pos->lnum;
941 newindent = get_indent();
942 }
943 }
944 }
945 }
946 }
947 else /* Not a comment line */
948# endif
949 {
950 /* Find last non-blank in line */
951 p = ptr + STRLEN(ptr) - 1;
Bram Moolenaar1c465442017-03-12 20:10:05 +0100952 while (p > ptr && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953 --p;
954 last_char = *p;
955
956 /*
957 * find the character just before the '{' or ';'
958 */
959 if (last_char == '{' || last_char == ';')
960 {
961 if (p > ptr)
962 --p;
Bram Moolenaar1c465442017-03-12 20:10:05 +0100963 while (p > ptr && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 --p;
965 }
966 /*
967 * Try to catch lines that are split over multiple
968 * lines. eg:
969 * if (condition &&
970 * condition) {
971 * Should line up here!
972 * }
973 */
974 if (*p == ')')
975 {
976 curwin->w_cursor.col = (colnr_T)(p - ptr);
977 if ((pos = findmatch(NULL, '(')) != NULL)
978 {
979 curwin->w_cursor.lnum = pos->lnum;
980 newindent = get_indent();
981 ptr = ml_get_curline();
982 }
983 }
984 /*
985 * If last character is '{' do indent, without
986 * checking for "if" and the like.
987 */
988 if (last_char == '{')
989 {
990 did_si = TRUE; /* do indent */
991 no_si = TRUE; /* don't delete it when '{' typed */
992 }
993 /*
994 * Look for "if" and the like, use 'cinwords'.
995 * Don't do this if the previous line ended in ';' or
996 * '}'.
997 */
998 else if (last_char != ';' && last_char != '}'
999 && cin_is_cinword(ptr))
1000 did_si = TRUE;
1001 }
1002 }
1003 else /* dir == BACKWARD */
1004 {
1005 /*
1006 * Skip preprocessor directives, unless they are
1007 * recognised as comments.
1008 */
1009 if (
1010# ifdef FEAT_COMMENTS
1011 lead_len == 0 &&
1012# endif
1013 ptr[0] == '#')
1014 {
1015 int was_backslashed = FALSE;
1016
1017 while ((ptr[0] == '#' || was_backslashed) &&
1018 curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
1019 {
1020 if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
1021 was_backslashed = TRUE;
1022 else
1023 was_backslashed = FALSE;
1024 ptr = ml_get(++curwin->w_cursor.lnum);
1025 }
1026 if (was_backslashed)
1027 newindent = 0; /* Got to end of file */
1028 else
1029 newindent = get_indent();
1030 }
1031 p = skipwhite(ptr);
1032 if (*p == '}') /* if line starts with '}': do indent */
1033 did_si = TRUE;
1034 else /* can delete indent when '{' typed */
1035 can_si_back = TRUE;
1036 }
1037 curwin->w_cursor = old_cursor;
1038 }
1039 if (do_si)
1040 can_si = TRUE;
1041#endif /* FEAT_SMARTINDENT */
1042
1043 did_ai = TRUE;
1044 }
1045
1046#ifdef FEAT_COMMENTS
1047 /*
1048 * Find out if the current line starts with a comment leader.
1049 * This may then be inserted in front of the new line.
1050 */
1051 end_comment_pending = NUL;
1052 if (flags & OPENLINE_DO_COM)
Bram Moolenaar81340392012-06-06 16:12:59 +02001053 lead_len = get_leader_len(saved_line, &lead_flags, dir == BACKWARD, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054 else
1055 lead_len = 0;
1056 if (lead_len > 0)
1057 {
1058 char_u *lead_repl = NULL; /* replaces comment leader */
1059 int lead_repl_len = 0; /* length of *lead_repl */
1060 char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */
1061 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
1062 char_u *comment_end = NULL; /* where lead_end has been found */
1063 int extra_space = FALSE; /* append extra space */
1064 int current_flag;
1065 int require_blank = FALSE; /* requires blank after middle */
1066 char_u *p2;
1067
1068 /*
1069 * If the comment leader has the start, middle or end flag, it may not
1070 * be used or may be replaced with the middle leader.
1071 */
1072 for (p = lead_flags; *p && *p != ':'; ++p)
1073 {
1074 if (*p == COM_BLANK)
1075 {
1076 require_blank = TRUE;
1077 continue;
1078 }
1079 if (*p == COM_START || *p == COM_MIDDLE)
1080 {
1081 current_flag = *p;
1082 if (*p == COM_START)
1083 {
1084 /*
1085 * Doing "O" on a start of comment does not insert leader.
1086 */
1087 if (dir == BACKWARD)
1088 {
1089 lead_len = 0;
1090 break;
1091 }
1092
1093 /* find start of middle part */
1094 (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
1095 require_blank = FALSE;
1096 }
1097
1098 /*
1099 * Isolate the strings of the middle and end leader.
1100 */
1101 while (*p && p[-1] != ':') /* find end of middle flags */
1102 {
1103 if (*p == COM_BLANK)
1104 require_blank = TRUE;
1105 ++p;
1106 }
1107 (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
1108
1109 while (*p && p[-1] != ':') /* find end of end flags */
1110 {
1111 /* Check whether we allow automatic ending of comments */
1112 if (*p == COM_AUTO_END)
1113 end_comment_pending = -1; /* means we want to set it */
1114 ++p;
1115 }
1116 n = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
1117
1118 if (end_comment_pending == -1) /* we can set it now */
1119 end_comment_pending = lead_end[n - 1];
1120
1121 /*
1122 * If the end of the comment is in the same line, don't use
1123 * the comment leader.
1124 */
1125 if (dir == FORWARD)
1126 {
1127 for (p = saved_line + lead_len; *p; ++p)
1128 if (STRNCMP(p, lead_end, n) == 0)
1129 {
1130 comment_end = p;
1131 lead_len = 0;
1132 break;
1133 }
1134 }
1135
1136 /*
1137 * Doing "o" on a start of comment inserts the middle leader.
1138 */
1139 if (lead_len > 0)
1140 {
1141 if (current_flag == COM_START)
1142 {
1143 lead_repl = lead_middle;
1144 lead_repl_len = (int)STRLEN(lead_middle);
1145 }
1146
1147 /*
1148 * If we have hit RETURN immediately after the start
1149 * comment leader, then put a space after the middle
1150 * comment leader on the next line.
1151 */
Bram Moolenaar1c465442017-03-12 20:10:05 +01001152 if (!VIM_ISWHITE(saved_line[lead_len - 1])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 && ((p_extra != NULL
1154 && (int)curwin->w_cursor.col == lead_len)
1155 || (p_extra == NULL
1156 && saved_line[lead_len] == NUL)
1157 || require_blank))
1158 extra_space = TRUE;
1159 }
1160 break;
1161 }
1162 if (*p == COM_END)
1163 {
1164 /*
1165 * Doing "o" on the end of a comment does not insert leader.
1166 * Remember where the end is, might want to use it to find the
1167 * start (for C-comments).
1168 */
1169 if (dir == FORWARD)
1170 {
1171 comment_end = skipwhite(saved_line);
1172 lead_len = 0;
1173 break;
1174 }
1175
1176 /*
1177 * Doing "O" on the end of a comment inserts the middle leader.
1178 * Find the string for the middle leader, searching backwards.
1179 */
1180 while (p > curbuf->b_p_com && *p != ',')
1181 --p;
1182 for (lead_repl = p; lead_repl > curbuf->b_p_com
1183 && lead_repl[-1] != ':'; --lead_repl)
1184 ;
1185 lead_repl_len = (int)(p - lead_repl);
1186
1187 /* We can probably always add an extra space when doing "O" on
1188 * the comment-end */
1189 extra_space = TRUE;
1190
1191 /* Check whether we allow automatic ending of comments */
1192 for (p2 = p; *p2 && *p2 != ':'; p2++)
1193 {
1194 if (*p2 == COM_AUTO_END)
1195 end_comment_pending = -1; /* means we want to set it */
1196 }
1197 if (end_comment_pending == -1)
1198 {
1199 /* Find last character in end-comment string */
1200 while (*p2 && *p2 != ',')
1201 p2++;
1202 end_comment_pending = p2[-1];
1203 }
1204 break;
1205 }
1206 if (*p == COM_FIRST)
1207 {
1208 /*
1209 * Comment leader for first line only: Don't repeat leader
1210 * when using "O", blank out leader when using "o".
1211 */
1212 if (dir == BACKWARD)
1213 lead_len = 0;
1214 else
1215 {
1216 lead_repl = (char_u *)"";
1217 lead_repl_len = 0;
1218 }
1219 break;
1220 }
1221 }
1222 if (lead_len)
1223 {
Bram Moolenaardc7e85e2012-06-20 12:40:08 +02001224 /* allocate buffer (may concatenate p_extra later) */
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02001225 leader = alloc(lead_len + lead_repl_len + extra_space + extra_len
Bram Moolenaardc7e85e2012-06-20 12:40:08 +02001226 + (second_line_indent > 0 ? second_line_indent : 0) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227 allocated = leader; /* remember to free it later */
1228
1229 if (leader == NULL)
1230 lead_len = 0;
1231 else
1232 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00001233 vim_strncpy(leader, saved_line, lead_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234
1235 /*
1236 * Replace leader with lead_repl, right or left adjusted
1237 */
1238 if (lead_repl != NULL)
1239 {
1240 int c = 0;
1241 int off = 0;
1242
Bram Moolenaard7d5b472009-11-11 16:30:08 +00001243 for (p = lead_flags; *p != NUL && *p != ':'; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 {
1245 if (*p == COM_RIGHT || *p == COM_LEFT)
Bram Moolenaard7d5b472009-11-11 16:30:08 +00001246 c = *p++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247 else if (VIM_ISDIGIT(*p) || *p == '-')
1248 off = getdigits(&p);
Bram Moolenaard7d5b472009-11-11 16:30:08 +00001249 else
1250 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251 }
1252 if (c == COM_RIGHT) /* right adjusted leader */
1253 {
1254 /* find last non-white in the leader to line up with */
1255 for (p = leader + lead_len - 1; p > leader
Bram Moolenaar1c465442017-03-12 20:10:05 +01001256 && VIM_ISWHITE(*p); --p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 ++p;
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001259
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001260 /* Compute the length of the replaced characters in
1261 * screen characters, not bytes. */
1262 {
1263 int repl_size = vim_strnsize(lead_repl,
1264 lead_repl_len);
1265 int old_size = 0;
1266 char_u *endp = p;
1267 int l;
1268
1269 while (old_size < repl_size && p > leader)
1270 {
Bram Moolenaar91acfff2017-03-12 19:22:36 +01001271 MB_PTR_BACK(leader, p);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001272 old_size += ptr2cells(p);
1273 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001274 l = lead_repl_len - (int)(endp - p);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001275 if (l != 0)
1276 mch_memmove(endp + l, endp,
1277 (size_t)((leader + lead_len) - endp));
1278 lead_len += l;
1279 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001280 mch_memmove(p, lead_repl, (size_t)lead_repl_len);
1281 if (p + lead_repl_len > leader + lead_len)
1282 p[lead_repl_len] = NUL;
1283
1284 /* blank-out any other chars from the old leader. */
1285 while (--p >= leader)
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001286 {
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001287 int l = mb_head_off(leader, p);
1288
1289 if (l > 1)
1290 {
1291 p -= l;
1292 if (ptr2cells(p) > 1)
1293 {
1294 p[1] = ' ';
1295 --l;
1296 }
1297 mch_memmove(p + 1, p + l + 1,
1298 (size_t)((leader + lead_len) - (p + l + 1)));
1299 lead_len -= l;
1300 *p = ' ';
1301 }
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01001302 else if (!VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303 *p = ' ';
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001304 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 }
1306 else /* left adjusted leader */
1307 {
1308 p = skipwhite(leader);
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01001309
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001310 /* Compute the length of the replaced characters in
1311 * screen characters, not bytes. Move the part that is
1312 * not to be overwritten. */
1313 {
1314 int repl_size = vim_strnsize(lead_repl,
1315 lead_repl_len);
1316 int i;
1317 int l;
1318
Bram Moolenaardc633cf2016-04-23 14:33:19 +02001319 for (i = 0; i < lead_len && p[i] != NUL; i += l)
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001320 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001321 l = (*mb_ptr2len)(p + i);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001322 if (vim_strnsize(p, i + l) > repl_size)
1323 break;
1324 }
1325 if (i != lead_repl_len)
1326 {
1327 mch_memmove(p + lead_repl_len, p + i,
Bram Moolenaar2d7ff052009-11-17 15:08:26 +00001328 (size_t)(lead_len - i - (p - leader)));
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001329 lead_len += lead_repl_len - i;
1330 }
1331 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332 mch_memmove(p, lead_repl, (size_t)lead_repl_len);
1333
1334 /* Replace any remaining non-white chars in the old
1335 * leader by spaces. Keep Tabs, the indent must
1336 * remain the same. */
1337 for (p += lead_repl_len; p < leader + lead_len; ++p)
Bram Moolenaar1c465442017-03-12 20:10:05 +01001338 if (!VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339 {
1340 /* Don't put a space before a TAB. */
1341 if (p + 1 < leader + lead_len && p[1] == TAB)
1342 {
1343 --lead_len;
1344 mch_memmove(p, p + 1,
1345 (leader + lead_len) - p);
1346 }
1347 else
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001348 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001349 int l = (*mb_ptr2len)(p);
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001350
1351 if (l > 1)
1352 {
1353 if (ptr2cells(p) > 1)
1354 {
1355 /* Replace a double-wide char with
1356 * two spaces */
1357 --l;
1358 *p++ = ' ';
1359 }
1360 mch_memmove(p + 1, p + l,
1361 (leader + lead_len) - p);
1362 lead_len -= l - 1;
1363 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001364 *p = ' ';
Bram Moolenaar21cf8232004-07-16 20:18:37 +00001365 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001366 }
1367 *p = NUL;
1368 }
1369
1370 /* Recompute the indent, it may have changed. */
1371 if (curbuf->b_p_ai
1372#ifdef FEAT_SMARTINDENT
1373 || do_si
1374#endif
1375 )
Bram Moolenaar04958cb2018-06-23 19:23:02 +02001376#ifdef FEAT_VARTABS
1377 newindent = get_indent_str_vtab(leader, curbuf->b_p_ts,
1378 curbuf->b_p_vts_array, FALSE);
1379#else
1380 newindent = get_indent_str(leader,
1381 (int)curbuf->b_p_ts, FALSE);
1382#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383
1384 /* Add the indent offset */
1385 if (newindent + off < 0)
1386 {
1387 off = -newindent;
1388 newindent = 0;
1389 }
1390 else
1391 newindent += off;
1392
1393 /* Correct trailing spaces for the shift, so that
1394 * alignment remains equal. */
1395 while (off > 0 && lead_len > 0
1396 && leader[lead_len - 1] == ' ')
1397 {
1398 /* Don't do it when there is a tab before the space */
1399 if (vim_strchr(skipwhite(leader), '\t') != NULL)
1400 break;
1401 --lead_len;
1402 --off;
1403 }
1404
1405 /* If the leader ends in white space, don't add an
1406 * extra space */
Bram Moolenaar1c465442017-03-12 20:10:05 +01001407 if (lead_len > 0 && VIM_ISWHITE(leader[lead_len - 1]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001408 extra_space = FALSE;
1409 leader[lead_len] = NUL;
1410 }
1411
1412 if (extra_space)
1413 {
1414 leader[lead_len++] = ' ';
1415 leader[lead_len] = NUL;
1416 }
1417
1418 newcol = lead_len;
1419
1420 /*
1421 * if a new indent will be set below, remove the indent that
1422 * is in the comment leader
1423 */
1424 if (newindent
1425#ifdef FEAT_SMARTINDENT
1426 || did_si
1427#endif
1428 )
1429 {
Bram Moolenaar1c465442017-03-12 20:10:05 +01001430 while (lead_len && VIM_ISWHITE(*leader))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431 {
1432 --lead_len;
1433 --newcol;
1434 ++leader;
1435 }
1436 }
1437
1438 }
1439#ifdef FEAT_SMARTINDENT
1440 did_si = can_si = FALSE;
1441#endif
1442 }
1443 else if (comment_end != NULL)
1444 {
1445 /*
1446 * We have finished a comment, so we don't use the leader.
1447 * If this was a C-comment and 'ai' or 'si' is set do a normal
1448 * indent to align with the line containing the start of the
1449 * comment.
1450 */
1451 if (comment_end[0] == '*' && comment_end[1] == '/' &&
1452 (curbuf->b_p_ai
1453#ifdef FEAT_SMARTINDENT
1454 || do_si
1455#endif
1456 ))
1457 {
1458 old_cursor = curwin->w_cursor;
1459 curwin->w_cursor.col = (colnr_T)(comment_end - saved_line);
1460 if ((pos = findmatch(NULL, NUL)) != NULL)
1461 {
1462 curwin->w_cursor.lnum = pos->lnum;
1463 newindent = get_indent();
1464 }
1465 curwin->w_cursor = old_cursor;
1466 }
1467 }
1468 }
1469#endif
1470
1471 /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
1472 if (p_extra != NULL)
1473 {
1474 *p_extra = saved_char; /* restore char that NUL replaced */
1475
1476 /*
1477 * When 'ai' set or "flags" has OPENLINE_DELSPACES, skip to the first
1478 * non-blank.
1479 *
1480 * When in REPLACE mode, put the deleted blanks on the replace stack,
1481 * preceded by a NUL, so they can be put back when a BS is entered.
1482 */
1483 if (REPLACE_NORMAL(State))
1484 replace_push(NUL); /* end of extra blanks */
1485 if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES))
1486 {
1487 while ((*p_extra == ' ' || *p_extra == '\t')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 && (!enc_utf8
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01001489 || !utf_iscomposing(utf_ptr2char(p_extra + 1))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 {
1491 if (REPLACE_NORMAL(State))
1492 replace_push(*p_extra);
1493 ++p_extra;
1494 ++less_cols_off;
1495 }
1496 }
1497 if (*p_extra != NUL)
1498 did_ai = FALSE; /* append some text, don't truncate now */
1499
1500 /* columns for marks adjusted for removed columns */
1501 less_cols = (int)(p_extra - saved_line);
1502 }
1503
1504 if (p_extra == NULL)
1505 p_extra = (char_u *)""; /* append empty line */
1506
1507#ifdef FEAT_COMMENTS
1508 /* concatenate leader and p_extra, if there is a leader */
1509 if (lead_len)
1510 {
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02001511 if (flags & OPENLINE_COM_LIST && second_line_indent > 0)
1512 {
1513 int i;
Bram Moolenaar36105782012-06-14 20:59:25 +02001514 int padding = second_line_indent
1515 - (newindent + (int)STRLEN(leader));
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02001516
1517 /* Here whitespace is inserted after the comment char.
1518 * Below, set_indent(newindent, SIN_INSERT) will insert the
1519 * whitespace needed before the comment char. */
1520 for (i = 0; i < padding; i++)
1521 {
1522 STRCAT(leader, " ");
Bram Moolenaar5fb9ec52012-07-25 16:10:03 +02001523 less_cols--;
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02001524 newcol++;
1525 }
1526 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 STRCAT(leader, p_extra);
1528 p_extra = leader;
1529 did_ai = TRUE; /* So truncating blanks works with comments */
1530 less_cols -= lead_len;
1531 }
1532 else
1533 end_comment_pending = NUL; /* turns out there was no leader */
1534#endif
1535
1536 old_cursor = curwin->w_cursor;
1537 if (dir == BACKWARD)
1538 --curwin->w_cursor.lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539 if (!(State & VREPLACE_FLAG) || old_cursor.lnum >= orig_line_count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001540 {
1541 if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, FALSE)
1542 == FAIL)
1543 goto theend;
1544 /* Postpone calling changed_lines(), because it would mess up folding
Bram Moolenaar82faa252016-06-04 20:14:07 +02001545 * with markers.
1546 * Skip mark_adjust when adding a line after the last one, there can't
Bram Moolenaarf58a8472017-03-05 18:03:04 +01001547 * be marks there. But still needed in diff mode. */
1548 if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
1549#ifdef FEAT_DIFF
1550 || curwin->w_p_diff
1551#endif
1552 )
Bram Moolenaar82faa252016-06-04 20:14:07 +02001553 mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001554 did_append = TRUE;
1555 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001556 else
1557 {
1558 /*
1559 * In VREPLACE mode we are starting to replace the next line.
1560 */
1561 curwin->w_cursor.lnum++;
1562 if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed)
1563 {
1564 /* In case we NL to a new line, BS to the previous one, and NL
1565 * again, we don't want to save the new line for undo twice.
1566 */
1567 (void)u_save_cursor(); /* errors are ignored! */
1568 vr_lines_changed++;
1569 }
1570 ml_replace(curwin->w_cursor.lnum, p_extra, TRUE);
1571 changed_bytes(curwin->w_cursor.lnum, 0);
1572 curwin->w_cursor.lnum--;
1573 did_append = FALSE;
1574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575
1576 if (newindent
1577#ifdef FEAT_SMARTINDENT
1578 || did_si
1579#endif
1580 )
1581 {
1582 ++curwin->w_cursor.lnum;
1583#ifdef FEAT_SMARTINDENT
1584 if (did_si)
1585 {
Bram Moolenaar75a8d742014-05-07 15:10:21 +02001586 int sw = (int)get_sw_value(curbuf);
Bram Moolenaar14f24742012-08-08 18:01:05 +02001587
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588 if (p_sr)
Bram Moolenaar14f24742012-08-08 18:01:05 +02001589 newindent -= newindent % sw;
1590 newindent += sw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001591 }
1592#endif
Bram Moolenaar5002c292007-07-24 13:26:15 +00001593 /* Copy the indent */
1594 if (curbuf->b_p_ci)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001595 {
1596 (void)copy_indent(newindent, saved_line);
1597
1598 /*
1599 * Set the 'preserveindent' option so that any further screwing
1600 * with the line doesn't entirely destroy our efforts to preserve
1601 * it. It gets restored at the function end.
1602 */
1603 curbuf->b_p_pi = TRUE;
1604 }
1605 else
1606 (void)set_indent(newindent, SIN_INSERT);
1607 less_cols -= curwin->w_cursor.col;
1608
1609 ai_col = curwin->w_cursor.col;
1610
1611 /*
1612 * In REPLACE mode, for each character in the new indent, there must
1613 * be a NUL on the replace stack, for when it is deleted with BS
1614 */
1615 if (REPLACE_NORMAL(State))
1616 for (n = 0; n < (int)curwin->w_cursor.col; ++n)
1617 replace_push(NUL);
1618 newcol += curwin->w_cursor.col;
1619#ifdef FEAT_SMARTINDENT
1620 if (no_si)
1621 did_si = FALSE;
1622#endif
1623 }
1624
1625#ifdef FEAT_COMMENTS
1626 /*
1627 * In REPLACE mode, for each character in the extra leader, there must be
1628 * a NUL on the replace stack, for when it is deleted with BS.
1629 */
1630 if (REPLACE_NORMAL(State))
1631 while (lead_len-- > 0)
1632 replace_push(NUL);
1633#endif
1634
1635 curwin->w_cursor = old_cursor;
1636
1637 if (dir == FORWARD)
1638 {
1639 if (trunc_line || (State & INSERT))
1640 {
1641 /* truncate current line at cursor */
1642 saved_line[curwin->w_cursor.col] = NUL;
1643 /* Remove trailing white space, unless OPENLINE_KEEPTRAIL used. */
1644 if (trunc_line && !(flags & OPENLINE_KEEPTRAIL))
1645 truncate_spaces(saved_line);
1646 ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
1647 saved_line = NULL;
1648 if (did_append)
1649 {
1650 changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
1651 curwin->w_cursor.lnum + 1, 1L);
1652 did_append = FALSE;
1653
1654 /* Move marks after the line break to the new line. */
1655 if (flags & OPENLINE_MARKFIX)
1656 mark_col_adjust(curwin->w_cursor.lnum,
1657 curwin->w_cursor.col + less_cols_off,
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001658 1L, (long)-less_cols, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001659 }
1660 else
1661 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
1662 }
1663
1664 /*
1665 * Put the cursor on the new line. Careful: the scrollup() above may
1666 * have moved w_cursor, we must use old_cursor.
1667 */
1668 curwin->w_cursor.lnum = old_cursor.lnum + 1;
1669 }
1670 if (did_append)
1671 changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L);
1672
1673 curwin->w_cursor.col = newcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 curwin->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +02001676#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 /*
1678 * In VREPLACE mode, we are handling the replace stack ourselves, so stop
1679 * fixthisline() from doing it (via change_indent()) by telling it we're in
1680 * normal INSERT mode.
1681 */
1682 if (State & VREPLACE_FLAG)
1683 {
1684 vreplace_mode = State; /* So we know to put things right later */
1685 State = INSERT;
1686 }
1687 else
1688 vreplace_mode = 0;
1689#endif
1690#ifdef FEAT_LISP
1691 /*
1692 * May do lisp indenting.
1693 */
1694 if (!p_paste
1695# ifdef FEAT_COMMENTS
1696 && leader == NULL
1697# endif
1698 && curbuf->b_p_lisp
1699 && curbuf->b_p_ai)
1700 {
1701 fixthisline(get_lisp_indent);
Bram Moolenaare2e69e42017-09-02 20:30:35 +02001702 ai_col = (colnr_T)getwhitecols_curline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 }
1704#endif
1705#ifdef FEAT_CINDENT
1706 /*
1707 * May do indenting after opening a new line.
1708 */
1709 if (!p_paste
1710 && (curbuf->b_p_cin
1711# ifdef FEAT_EVAL
1712 || *curbuf->b_p_inde != NUL
1713# endif
1714 )
1715 && in_cinkeys(dir == FORWARD
1716 ? KEY_OPEN_FORW
1717 : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
1718 {
1719 do_c_expr_indent();
Bram Moolenaare2e69e42017-09-02 20:30:35 +02001720 ai_col = (colnr_T)getwhitecols_curline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721 }
1722#endif
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +02001723#if defined(FEAT_LISP) || defined(FEAT_CINDENT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 if (vreplace_mode != 0)
1725 State = vreplace_mode;
1726#endif
1727
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 /*
1729 * Finally, VREPLACE gets the stuff on the new line, then puts back the
1730 * original line, and inserts the new stuff char by char, pushing old stuff
1731 * onto the replace stack (via ins_char()).
1732 */
1733 if (State & VREPLACE_FLAG)
1734 {
1735 /* Put new line in p_extra */
1736 p_extra = vim_strsave(ml_get_curline());
1737 if (p_extra == NULL)
1738 goto theend;
1739
1740 /* Put back original line */
1741 ml_replace(curwin->w_cursor.lnum, next_line, FALSE);
1742
1743 /* Insert new stuff into line again */
1744 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 curwin->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 ins_bytes(p_extra); /* will call changed_bytes() */
1747 vim_free(p_extra);
1748 next_line = NULL;
1749 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750
Bram Moolenaar24a2d722018-04-24 19:36:43 +02001751 retval = OK; /* success! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752theend:
1753 curbuf->b_p_pi = saved_pi;
1754 vim_free(saved_line);
1755 vim_free(next_line);
1756 vim_free(allocated);
1757 return retval;
1758}
1759
1760#if defined(FEAT_COMMENTS) || defined(PROTO)
1761/*
Bram Moolenaar2c019c82013-10-06 17:46:56 +02001762 * get_leader_len() returns the length in bytes of the prefix of the given
1763 * string which introduces a comment. If this string is not a comment then
1764 * 0 is returned.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 * When "flags" is not NULL, it is set to point to the flags of the recognized
1766 * comment leader.
1767 * "backward" must be true for the "O" command.
Bram Moolenaar81340392012-06-06 16:12:59 +02001768 * If "include_space" is set, include trailing whitespace while calculating the
1769 * length.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 */
1771 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01001772get_leader_len(
1773 char_u *line,
1774 char_u **flags,
1775 int backward,
1776 int include_space)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777{
1778 int i, j;
Bram Moolenaar81340392012-06-06 16:12:59 +02001779 int result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780 int got_com = FALSE;
1781 int found_one;
1782 char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
1783 char_u *string; /* pointer to comment string */
1784 char_u *list;
Bram Moolenaara4271d52011-05-10 13:38:27 +02001785 int middle_match_len = 0;
1786 char_u *prev_list;
Bram Moolenaar05da4282011-05-10 14:44:11 +02001787 char_u *saved_flags = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788
Bram Moolenaar81340392012-06-06 16:12:59 +02001789 result = i = 0;
Bram Moolenaar1c465442017-03-12 20:10:05 +01001790 while (VIM_ISWHITE(line[i])) /* leading white space is ignored */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 ++i;
1792
1793 /*
1794 * Repeat to match several nested comment strings.
1795 */
Bram Moolenaara4271d52011-05-10 13:38:27 +02001796 while (line[i] != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 {
1798 /*
1799 * scan through the 'comments' option for a match
1800 */
1801 found_one = FALSE;
1802 for (list = curbuf->b_p_com; *list; )
1803 {
Bram Moolenaara4271d52011-05-10 13:38:27 +02001804 /* Get one option part into part_buf[]. Advance "list" to next
1805 * one. Put "string" at start of string. */
1806 if (!got_com && flags != NULL)
1807 *flags = list; /* remember where flags started */
1808 prev_list = list;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809 (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
1810 string = vim_strchr(part_buf, ':');
1811 if (string == NULL) /* missing ':', ignore this part */
1812 continue;
1813 *string++ = NUL; /* isolate flags from string */
1814
Bram Moolenaara4271d52011-05-10 13:38:27 +02001815 /* If we found a middle match previously, use that match when this
1816 * is not a middle or end. */
1817 if (middle_match_len != 0
1818 && vim_strchr(part_buf, COM_MIDDLE) == NULL
1819 && vim_strchr(part_buf, COM_END) == NULL)
1820 break;
1821
1822 /* When we already found a nested comment, only accept further
1823 * nested comments. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
1825 continue;
1826
Bram Moolenaara4271d52011-05-10 13:38:27 +02001827 /* When 'O' flag present and using "O" command skip this one. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL)
1829 continue;
1830
Bram Moolenaara4271d52011-05-10 13:38:27 +02001831 /* Line contents and string must match.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 * When string starts with white space, must have some white space
1833 * (but the amount does not need to match, there might be a mix of
Bram Moolenaara4271d52011-05-10 13:38:27 +02001834 * TABs and spaces). */
Bram Moolenaar1c465442017-03-12 20:10:05 +01001835 if (VIM_ISWHITE(string[0]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836 {
Bram Moolenaar1c465442017-03-12 20:10:05 +01001837 if (i == 0 || !VIM_ISWHITE(line[i - 1]))
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001838 continue; /* missing white space */
Bram Moolenaar1c465442017-03-12 20:10:05 +01001839 while (VIM_ISWHITE(string[0]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840 ++string;
1841 }
1842 for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
1843 ;
1844 if (string[j] != NUL)
Bram Moolenaara4271d52011-05-10 13:38:27 +02001845 continue; /* string doesn't match */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846
Bram Moolenaara4271d52011-05-10 13:38:27 +02001847 /* When 'b' flag used, there must be white space or an
1848 * end-of-line after the string in the line. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 if (vim_strchr(part_buf, COM_BLANK) != NULL
Bram Moolenaar1c465442017-03-12 20:10:05 +01001850 && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 continue;
1852
Bram Moolenaara4271d52011-05-10 13:38:27 +02001853 /* We have found a match, stop searching unless this is a middle
1854 * comment. The middle comment can be a substring of the end
1855 * comment in which case it's better to return the length of the
1856 * end comment and its flags. Thus we keep searching with middle
1857 * and end matches and use an end match if it matches better. */
1858 if (vim_strchr(part_buf, COM_MIDDLE) != NULL)
1859 {
1860 if (middle_match_len == 0)
1861 {
1862 middle_match_len = j;
1863 saved_flags = prev_list;
1864 }
1865 continue;
1866 }
1867 if (middle_match_len != 0 && j > middle_match_len)
1868 /* Use this match instead of the middle match, since it's a
1869 * longer thus better match. */
1870 middle_match_len = 0;
1871
1872 if (middle_match_len == 0)
1873 i += j;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 found_one = TRUE;
1875 break;
1876 }
1877
Bram Moolenaara4271d52011-05-10 13:38:27 +02001878 if (middle_match_len != 0)
1879 {
1880 /* Use the previously found middle match after failing to find a
1881 * match with an end. */
1882 if (!got_com && flags != NULL)
1883 *flags = saved_flags;
1884 i += middle_match_len;
1885 found_one = TRUE;
1886 }
1887
1888 /* No match found, stop scanning. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 if (!found_one)
1890 break;
1891
Bram Moolenaar81340392012-06-06 16:12:59 +02001892 result = i;
1893
Bram Moolenaara4271d52011-05-10 13:38:27 +02001894 /* Include any trailing white space. */
Bram Moolenaar1c465442017-03-12 20:10:05 +01001895 while (VIM_ISWHITE(line[i]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 ++i;
1897
Bram Moolenaar81340392012-06-06 16:12:59 +02001898 if (include_space)
1899 result = i;
1900
Bram Moolenaara4271d52011-05-10 13:38:27 +02001901 /* If this comment doesn't nest, stop here. */
1902 got_com = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 if (vim_strchr(part_buf, COM_NEST) == NULL)
1904 break;
1905 }
Bram Moolenaar81340392012-06-06 16:12:59 +02001906 return result;
1907}
Bram Moolenaara4271d52011-05-10 13:38:27 +02001908
Bram Moolenaar81340392012-06-06 16:12:59 +02001909/*
1910 * Return the offset at which the last comment in line starts. If there is no
1911 * comment in the whole line, -1 is returned.
1912 *
1913 * When "flags" is not null, it is set to point to the flags describing the
1914 * recognized comment leader.
1915 */
1916 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01001917get_last_leader_offset(char_u *line, char_u **flags)
Bram Moolenaar81340392012-06-06 16:12:59 +02001918{
1919 int result = -1;
1920 int i, j;
1921 int lower_check_bound = 0;
1922 char_u *string;
1923 char_u *com_leader;
1924 char_u *com_flags;
1925 char_u *list;
1926 int found_one;
1927 char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
1928
1929 /*
1930 * Repeat to match several nested comment strings.
1931 */
1932 i = (int)STRLEN(line);
1933 while (--i >= lower_check_bound)
1934 {
1935 /*
1936 * scan through the 'comments' option for a match
1937 */
1938 found_one = FALSE;
1939 for (list = curbuf->b_p_com; *list; )
1940 {
1941 char_u *flags_save = list;
1942
1943 /*
1944 * Get one option part into part_buf[]. Advance list to next one.
1945 * put string at start of string.
1946 */
1947 (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
1948 string = vim_strchr(part_buf, ':');
1949 if (string == NULL) /* If everything is fine, this cannot actually
1950 * happen. */
1951 {
1952 continue;
1953 }
1954 *string++ = NUL; /* Isolate flags from string. */
1955 com_leader = string;
1956
1957 /*
1958 * Line contents and string must match.
1959 * When string starts with white space, must have some white space
1960 * (but the amount does not need to match, there might be a mix of
1961 * TABs and spaces).
1962 */
Bram Moolenaar1c465442017-03-12 20:10:05 +01001963 if (VIM_ISWHITE(string[0]))
Bram Moolenaar81340392012-06-06 16:12:59 +02001964 {
Bram Moolenaar1c465442017-03-12 20:10:05 +01001965 if (i == 0 || !VIM_ISWHITE(line[i - 1]))
Bram Moolenaar81340392012-06-06 16:12:59 +02001966 continue;
Bram Moolenaar53932812018-12-07 21:08:49 +01001967 while (VIM_ISWHITE(*string))
Bram Moolenaar81340392012-06-06 16:12:59 +02001968 ++string;
1969 }
1970 for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
1971 /* do nothing */;
1972 if (string[j] != NUL)
1973 continue;
1974
1975 /*
1976 * When 'b' flag used, there must be white space or an
1977 * end-of-line after the string in the line.
1978 */
1979 if (vim_strchr(part_buf, COM_BLANK) != NULL
Bram Moolenaar1c465442017-03-12 20:10:05 +01001980 && !VIM_ISWHITE(line[i + j]) && line[i + j] != NUL)
Bram Moolenaar81340392012-06-06 16:12:59 +02001981 continue;
Bram Moolenaar53932812018-12-07 21:08:49 +01001982
Bram Moolenaar4af72592018-12-09 15:00:52 +01001983 if (vim_strchr(part_buf, COM_MIDDLE) != NULL)
Bram Moolenaar53932812018-12-07 21:08:49 +01001984 {
Bram Moolenaar4af72592018-12-09 15:00:52 +01001985 // For a middlepart comment, only consider it to match if
1986 // everything before the current position in the line is
1987 // whitespace. Otherwise we would think we are inside a
1988 // comment if the middle part appears somewhere in the middle
1989 // of the line. E.g. for C the "*" appears often.
Bram Moolenaar53932812018-12-07 21:08:49 +01001990 for (j = 0; VIM_ISWHITE(line[j]) && j <= i; j++)
1991 ;
1992 if (j < i)
1993 continue;
Bram Moolenaar81340392012-06-06 16:12:59 +02001994 }
1995
1996 /*
1997 * We have found a match, stop searching.
1998 */
1999 found_one = TRUE;
2000
2001 if (flags)
2002 *flags = flags_save;
2003 com_flags = flags_save;
2004
2005 break;
2006 }
2007
2008 if (found_one)
2009 {
2010 char_u part_buf2[COM_MAX_LEN]; /* buffer for one option part */
2011 int len1, len2, off;
2012
2013 result = i;
2014 /*
2015 * If this comment nests, continue searching.
2016 */
2017 if (vim_strchr(part_buf, COM_NEST) != NULL)
2018 continue;
2019
2020 lower_check_bound = i;
2021
2022 /* Let's verify whether the comment leader found is a substring
2023 * of other comment leaders. If it is, let's adjust the
2024 * lower_check_bound so that we make sure that we have determined
2025 * the comment leader correctly.
2026 */
2027
Bram Moolenaar1c465442017-03-12 20:10:05 +01002028 while (VIM_ISWHITE(*com_leader))
Bram Moolenaar81340392012-06-06 16:12:59 +02002029 ++com_leader;
2030 len1 = (int)STRLEN(com_leader);
2031
2032 for (list = curbuf->b_p_com; *list; )
2033 {
2034 char_u *flags_save = list;
2035
2036 (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
2037 if (flags_save == com_flags)
2038 continue;
2039 string = vim_strchr(part_buf2, ':');
2040 ++string;
Bram Moolenaar1c465442017-03-12 20:10:05 +01002041 while (VIM_ISWHITE(*string))
Bram Moolenaar81340392012-06-06 16:12:59 +02002042 ++string;
2043 len2 = (int)STRLEN(string);
2044 if (len2 == 0)
2045 continue;
2046
2047 /* Now we have to verify whether string ends with a substring
2048 * beginning the com_leader. */
2049 for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2;)
2050 {
2051 --off;
2052 if (!STRNCMP(string + off, com_leader, len2 - off))
2053 {
2054 if (i - off < lower_check_bound)
2055 lower_check_bound = i - off;
2056 }
2057 }
2058 }
2059 }
2060 }
2061 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062}
2063#endif
2064
2065/*
2066 * Return the number of window lines occupied by buffer line "lnum".
2067 */
2068 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002069plines(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070{
2071 return plines_win(curwin, lnum, TRUE);
2072}
2073
2074 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002075plines_win(
2076 win_T *wp,
2077 linenr_T lnum,
2078 int winheight) /* when TRUE limit to window height */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079{
2080#if defined(FEAT_DIFF) || defined(PROTO)
2081 /* Check for filler lines above this buffer line. When folded the result
2082 * is one line anyway. */
2083 return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum);
2084}
2085
2086 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002087plines_nofill(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088{
2089 return plines_win_nofill(curwin, lnum, TRUE);
2090}
2091
2092 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002093plines_win_nofill(
2094 win_T *wp,
2095 linenr_T lnum,
2096 int winheight) /* when TRUE limit to window height */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097{
2098#endif
2099 int lines;
2100
2101 if (!wp->w_p_wrap)
2102 return 1;
2103
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 if (wp->w_width == 0)
2105 return 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002106
2107#ifdef FEAT_FOLDING
2108 /* A folded lines is handled just like an empty line. */
2109 /* NOTE: Caller must handle lines that are MAYBE folded. */
2110 if (lineFolded(wp, lnum) == TRUE)
2111 return 1;
2112#endif
2113
2114 lines = plines_win_nofold(wp, lnum);
2115 if (winheight > 0 && lines > wp->w_height)
2116 return (int)wp->w_height;
2117 return lines;
2118}
2119
2120/*
2121 * Return number of window lines physical line "lnum" will occupy in window
2122 * "wp". Does not care about folding, 'wrap' or 'diff'.
2123 */
2124 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002125plines_win_nofold(win_T *wp, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126{
2127 char_u *s;
2128 long col;
2129 int width;
2130
2131 s = ml_get_buf(wp->w_buffer, lnum, FALSE);
2132 if (*s == NUL) /* empty line */
2133 return 1;
2134 col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
2135
2136 /*
2137 * If list mode is on, then the '$' at the end of the line may take up one
2138 * extra column.
2139 */
2140 if (wp->w_p_list && lcs_eol != NUL)
2141 col += 1;
2142
2143 /*
Bram Moolenaar64486672010-05-16 15:46:46 +02002144 * Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 */
Bram Moolenaar02631462017-09-22 15:20:32 +02002146 width = wp->w_width - win_col_off(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 if (width <= 0)
2148 return 32000;
2149 if (col <= width)
2150 return 1;
2151 col -= width;
2152 width += win_col_off2(wp);
2153 return (col + (width - 1)) / width + 1;
2154}
2155
2156/*
2157 * Like plines_win(), but only reports the number of physical screen lines
2158 * used from the start of the line to the given column number.
2159 */
2160 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002161plines_win_col(win_T *wp, linenr_T lnum, long column)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162{
2163 long col;
2164 char_u *s;
2165 int lines = 0;
2166 int width;
Bram Moolenaar597a4222014-06-25 14:39:50 +02002167 char_u *line;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168
2169#ifdef FEAT_DIFF
2170 /* Check for filler lines above this buffer line. When folded the result
2171 * is one line anyway. */
2172 lines = diff_check_fill(wp, lnum);
2173#endif
2174
2175 if (!wp->w_p_wrap)
2176 return lines + 1;
2177
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178 if (wp->w_width == 0)
2179 return lines + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180
Bram Moolenaar597a4222014-06-25 14:39:50 +02002181 line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182
2183 col = 0;
2184 while (*s != NUL && --column >= 0)
2185 {
Bram Moolenaar597a4222014-06-25 14:39:50 +02002186 col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01002187 MB_PTR_ADV(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002188 }
2189
2190 /*
2191 * If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
2192 * INSERT mode, then col must be adjusted so that it represents the last
2193 * screen position of the TAB. This only fixes an error when the TAB wraps
2194 * from one screen line to the next (when 'columns' is not a multiple of
2195 * 'ts') -- webb.
2196 */
2197 if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1))
Bram Moolenaar597a4222014-06-25 14:39:50 +02002198 col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002199
2200 /*
Bram Moolenaar64486672010-05-16 15:46:46 +02002201 * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202 */
Bram Moolenaar02631462017-09-22 15:20:32 +02002203 width = wp->w_width - win_col_off(wp);
Bram Moolenaar26470632006-10-24 19:12:40 +00002204 if (width <= 0)
2205 return 9999;
2206
2207 lines += 1;
2208 if (col > width)
2209 lines += (col - width) / (width + win_col_off2(wp)) + 1;
2210 return lines;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211}
2212
2213 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002214plines_m_win(win_T *wp, linenr_T first, linenr_T last)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002215{
2216 int count = 0;
2217
2218 while (first <= last)
2219 {
2220#ifdef FEAT_FOLDING
2221 int x;
2222
2223 /* Check if there are any really folded lines, but also included lines
2224 * that are maybe folded. */
2225 x = foldedCount(wp, first, NULL);
2226 if (x > 0)
2227 {
2228 ++count; /* count 1 for "+-- folded" line */
2229 first += x;
2230 }
2231 else
2232#endif
2233 {
2234#ifdef FEAT_DIFF
2235 if (first == wp->w_topline)
2236 count += plines_win_nofill(wp, first, TRUE) + wp->w_topfill;
2237 else
2238#endif
2239 count += plines_win(wp, first, TRUE);
2240 ++first;
2241 }
2242 }
2243 return (count);
2244}
2245
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246/*
2247 * Insert string "p" at the cursor position. Stops at a NUL byte.
2248 * Handles Replace mode and multi-byte characters.
2249 */
2250 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002251ins_bytes(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252{
2253 ins_bytes_len(p, (int)STRLEN(p));
2254}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256/*
2257 * Insert string "p" with length "len" at the cursor position.
2258 * Handles Replace mode and multi-byte characters.
2259 */
2260 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002261ins_bytes_len(char_u *p, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262{
2263 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264 int n;
2265
Bram Moolenaar176dd1e2008-06-21 14:30:28 +00002266 if (has_mbyte)
2267 for (i = 0; i < len; i += n)
2268 {
2269 if (enc_utf8)
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002270 // avoid reading past p[len]
Bram Moolenaar176dd1e2008-06-21 14:30:28 +00002271 n = utfc_ptr2len_len(p + i, len - i);
2272 else
2273 n = (*mb_ptr2len)(p + i);
2274 ins_char_bytes(p + i, n);
2275 }
2276 else
Bram Moolenaar176dd1e2008-06-21 14:30:28 +00002277 for (i = 0; i < len; ++i)
2278 ins_char(p[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280
2281/*
2282 * Insert or replace a single character at the cursor position.
2283 * When in REPLACE or VREPLACE mode, replace any existing character.
2284 * Caller must have prepared for undo.
2285 * For multi-byte characters we get the whole character, the caller must
2286 * convert bytes to a character.
2287 */
2288 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002289ins_char(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290{
Bram Moolenaar9a920d82012-06-01 15:21:02 +02002291 char_u buf[MB_MAXBYTES + 1];
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01002292 int n = (*mb_char2bytes)(c, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293
2294 /* When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte.
2295 * Happens for CTRL-Vu9900. */
2296 if (buf[0] == 0)
2297 buf[0] = '\n';
2298
2299 ins_char_bytes(buf, n);
2300}
2301
2302 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002303ins_char_bytes(char_u *buf, int charlen)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304{
2305 int c = buf[0];
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002306 int newlen; // nr of bytes inserted
2307 int oldlen; // nr of bytes deleted (0 when not replacing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 char_u *p;
2309 char_u *newp;
2310 char_u *oldp;
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002311 int linelen; // length of old line including NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 colnr_T col;
2313 linenr_T lnum = curwin->w_cursor.lnum;
2314 int i;
2315
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 /* Break tabs if needed. */
2317 if (virtual_active() && curwin->w_cursor.coladd > 0)
2318 coladvance_force(getviscol());
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319
2320 col = curwin->w_cursor.col;
2321 oldp = ml_get(lnum);
2322 linelen = (int)STRLEN(oldp) + 1;
2323
2324 /* The lengths default to the values for when not replacing. */
2325 oldlen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326 newlen = charlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327
2328 if (State & REPLACE_FLAG)
2329 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330 if (State & VREPLACE_FLAG)
2331 {
2332 colnr_T new_vcol = 0; /* init for GCC */
2333 colnr_T vcol;
2334 int old_list;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335
2336 /*
2337 * Disable 'list' temporarily, unless 'cpo' contains the 'L' flag.
2338 * Returns the old value of list, so when finished,
2339 * curwin->w_p_list should be set back to this.
2340 */
2341 old_list = curwin->w_p_list;
2342 if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
2343 curwin->w_p_list = FALSE;
2344
2345 /*
2346 * In virtual replace mode each character may replace one or more
2347 * characters (zero if it's a TAB). Count the number of bytes to
2348 * be deleted to make room for the new character, counting screen
2349 * cells. May result in adding spaces to fill a gap.
2350 */
2351 getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 new_vcol = vcol + chartabsize(buf, vcol);
2353 while (oldp[col + oldlen] != NUL && vcol < new_vcol)
2354 {
2355 vcol += chartabsize(oldp + col + oldlen, vcol);
2356 /* Don't need to remove a TAB that takes us to the right
2357 * position. */
2358 if (vcol > new_vcol && oldp[col + oldlen] == TAB)
2359 break;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002360 oldlen += (*mb_ptr2len)(oldp + col + oldlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002361 /* Deleted a bit too much, insert spaces. */
2362 if (vcol > new_vcol)
2363 newlen += vcol - new_vcol;
2364 }
2365 curwin->w_p_list = old_list;
2366 }
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002367 else if (oldp[col] != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 {
2369 /* normal replace */
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002370 oldlen = (*mb_ptr2len)(oldp + col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371 }
2372
2373
2374 /* Push the replaced bytes onto the replace stack, so that they can be
2375 * put back when BS is used. The bytes of a multi-byte character are
2376 * done the other way around, so that the first byte is popped off
2377 * first (it tells the byte length of the character). */
2378 replace_push(NUL);
2379 for (i = 0; i < oldlen; ++i)
2380 {
Bram Moolenaar2c994e82008-01-02 16:49:36 +00002381 if (has_mbyte)
2382 i += replace_push_mb(oldp + col + i) - 1;
2383 else
Bram Moolenaar2c994e82008-01-02 16:49:36 +00002384 replace_push(oldp[col + i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 }
2386 }
2387
2388 newp = alloc_check((unsigned)(linelen + newlen - oldlen));
2389 if (newp == NULL)
2390 return;
2391
2392 /* Copy bytes before the cursor. */
2393 if (col > 0)
2394 mch_memmove(newp, oldp, (size_t)col);
2395
2396 /* Copy bytes after the changed character(s). */
2397 p = newp + col;
Bram Moolenaar9ad89c62017-10-26 22:04:04 +02002398 if (linelen > col + oldlen)
2399 mch_memmove(p + newlen, oldp + col + oldlen,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400 (size_t)(linelen - col - oldlen));
2401
2402 /* Insert or overwrite the new character. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002403 mch_memmove(p, buf, charlen);
2404 i = charlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405
2406 /* Fill with spaces when necessary. */
2407 while (i < newlen)
2408 p[i++] = ' ';
2409
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002410 // Replace the line in the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411 ml_replace(lnum, newp, FALSE);
2412
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002413 // mark the buffer as changed and prepare for displaying
2414 inserted_bytes(lnum, col, newlen - oldlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415
2416 /*
2417 * If we're in Insert or Replace mode and 'showmatch' is set, then briefly
2418 * show the match for right parens and braces.
2419 */
2420 if (p_sm && (State & INSERT)
2421 && msg_silent == 0
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002422#ifdef FEAT_INS_EXPAND
2423 && !ins_compl_active()
2424#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 )
Bram Moolenaar8c7694a2013-01-17 17:02:05 +01002426 {
Bram Moolenaar8c7694a2013-01-17 17:02:05 +01002427 if (has_mbyte)
2428 showmatch(mb_ptr2char(buf));
2429 else
Bram Moolenaar8c7694a2013-01-17 17:02:05 +01002430 showmatch(c);
2431 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432
2433#ifdef FEAT_RIGHTLEFT
2434 if (!p_ri || (State & REPLACE_FLAG))
2435#endif
2436 {
2437 /* Normal insert: move cursor right */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 curwin->w_cursor.col += charlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439 }
2440 /*
2441 * TODO: should try to update w_row here, to avoid recomputing it later.
2442 */
2443}
2444
2445/*
2446 * Insert a string at the cursor position.
2447 * Note: Does NOT handle Replace mode.
2448 * Caller must have prepared for undo.
2449 */
2450 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002451ins_str(char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452{
2453 char_u *oldp, *newp;
2454 int newlen = (int)STRLEN(s);
2455 int oldlen;
2456 colnr_T col;
2457 linenr_T lnum = curwin->w_cursor.lnum;
2458
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 if (virtual_active() && curwin->w_cursor.coladd > 0)
2460 coladvance_force(getviscol());
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461
2462 col = curwin->w_cursor.col;
2463 oldp = ml_get(lnum);
2464 oldlen = (int)STRLEN(oldp);
2465
2466 newp = alloc_check((unsigned)(oldlen + newlen + 1));
2467 if (newp == NULL)
2468 return;
2469 if (col > 0)
2470 mch_memmove(newp, oldp, (size_t)col);
2471 mch_memmove(newp + col, s, (size_t)newlen);
2472 mch_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
2473 ml_replace(lnum, newp, FALSE);
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002474 inserted_bytes(lnum, col, newlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 curwin->w_cursor.col += newlen;
2476}
2477
2478/*
2479 * Delete one character under the cursor.
2480 * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line.
2481 * Caller must have prepared for undo.
2482 *
2483 * return FAIL for failure, OK otherwise
2484 */
2485 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002486del_char(int fixpos)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 if (has_mbyte)
2489 {
2490 /* Make sure the cursor is at the start of a character. */
2491 mb_adjust_cursor();
2492 if (*ml_get_cursor() == NUL)
2493 return FAIL;
2494 return del_chars(1L, fixpos);
2495 }
Bram Moolenaare3226be2005-12-18 22:10:00 +00002496 return del_bytes(1L, fixpos, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497}
2498
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499/*
2500 * Like del_bytes(), but delete characters instead of bytes.
2501 */
2502 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002503del_chars(long count, int fixpos)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504{
2505 long bytes = 0;
2506 long i;
2507 char_u *p;
2508 int l;
2509
2510 p = ml_get_cursor();
2511 for (i = 0; i < count && *p != NUL; ++i)
2512 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002513 l = (*mb_ptr2len)(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514 bytes += l;
2515 p += l;
2516 }
Bram Moolenaare3226be2005-12-18 22:10:00 +00002517 return del_bytes(bytes, fixpos, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519
2520/*
2521 * Delete "count" bytes under the cursor.
2522 * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line.
2523 * Caller must have prepared for undo.
2524 *
Bram Moolenaar191f18b2018-02-04 16:38:47 +01002525 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002526 */
2527 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002528del_bytes(
2529 long count,
2530 int fixpos_arg,
2531 int use_delcombine UNUSED) /* 'delcombine' option applies */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532{
2533 char_u *oldp, *newp;
2534 colnr_T oldlen;
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002535 colnr_T newlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 linenr_T lnum = curwin->w_cursor.lnum;
2537 colnr_T col = curwin->w_cursor.col;
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002538 int alloc_newp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 long movelen;
Bram Moolenaarca003e12006-03-17 23:19:38 +00002540 int fixpos = fixpos_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541
2542 oldp = ml_get(lnum);
2543 oldlen = (int)STRLEN(oldp);
2544
Bram Moolenaar191f18b2018-02-04 16:38:47 +01002545 /* Can't do anything when the cursor is on the NUL after the line. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546 if (col >= oldlen)
2547 return FAIL;
2548
Bram Moolenaar191f18b2018-02-04 16:38:47 +01002549 /* If "count" is zero there is nothing to do. */
2550 if (count == 0)
2551 return OK;
2552
2553 /* If "count" is negative the caller must be doing something wrong. */
2554 if (count < 1)
2555 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002556 siemsg("E950: Invalid count for del_bytes(): %ld", count);
Bram Moolenaar191f18b2018-02-04 16:38:47 +01002557 return FAIL;
2558 }
2559
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 /* If 'delcombine' is set and deleting (less than) one character, only
2561 * delete the last combining character. */
Bram Moolenaare3226be2005-12-18 22:10:00 +00002562 if (p_deco && use_delcombine && enc_utf8
2563 && utfc_ptr2len(oldp + col) >= count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002565 int cc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 int n;
2567
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002568 (void)utfc_ptr2char(oldp + col, cc);
2569 if (cc[0] != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 {
2571 /* Find the last composing char, there can be several. */
2572 n = col;
2573 do
2574 {
2575 col = n;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002576 count = utf_ptr2len(oldp + n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 n += count;
2578 } while (UTF_COMPOSINGLIKE(oldp + col, oldp + n));
2579 fixpos = 0;
2580 }
2581 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582
2583 /*
2584 * When count is too big, reduce it.
2585 */
2586 movelen = (long)oldlen - (long)col - count + 1; /* includes trailing NUL */
2587 if (movelen <= 1)
2588 {
2589 /*
2590 * If we just took off the last character of a non-blank line, and
Bram Moolenaarca003e12006-03-17 23:19:38 +00002591 * fixpos is TRUE, we don't want to end up positioned at the NUL,
2592 * unless "restart_edit" is set or 'virtualedit' contains "onemore".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 */
Bram Moolenaarca003e12006-03-17 23:19:38 +00002594 if (col > 0 && fixpos && restart_edit == 0
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002595 && (ve_flags & VE_ONEMORE) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 {
2597 --curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598 curwin->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599 if (has_mbyte)
2600 curwin->w_cursor.col -=
2601 (*mb_head_off)(oldp, oldp + curwin->w_cursor.col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 }
2603 count = oldlen - col;
2604 movelen = 1;
2605 }
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002606 newlen = oldlen - count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607
2608 /*
2609 * If the old line has been allocated the deletion can be done in the
2610 * existing line. Otherwise a new line has to be allocated
Bram Moolenaare21877a2008-02-13 09:58:14 +00002611 * Can't do this when using Netbeans, because we would need to invoke
2612 * netbeans_removed(), which deallocates the line. Let ml_replace() take
Bram Moolenaar1a509df2010-08-01 17:59:57 +02002613 * care of notifying Netbeans.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002616 if (netbeans_active())
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002617 alloc_newp = TRUE;
Bram Moolenaare21877a2008-02-13 09:58:14 +00002618 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002620 alloc_newp = !ml_line_alloced(); // check if oldp was allocated
2621 if (!alloc_newp)
2622 newp = oldp; // use same allocated memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 else
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002624 { // need to allocate a new line
2625 newp = alloc((unsigned)(newlen + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 if (newp == NULL)
2627 return FAIL;
2628 mch_memmove(newp, oldp, (size_t)col);
2629 }
2630 mch_memmove(newp + col, oldp + col + count, (size_t)movelen);
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002631 if (alloc_newp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 ml_replace(lnum, newp, FALSE);
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002633#ifdef FEAT_TEXT_PROP
2634 else
2635 {
2636 // Also move any following text properties.
2637 if (oldlen + 1 < curbuf->b_ml.ml_line_len)
2638 mch_memmove(newp + newlen + 1, oldp + oldlen + 1,
2639 (size_t)curbuf->b_ml.ml_line_len - oldlen - 1);
2640 curbuf->b_ml.ml_line_len -= count;
2641 }
2642#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643
Bram Moolenaar98aefe72018-12-13 22:20:09 +01002644 // mark the buffer as changed and prepare for displaying
Bram Moolenaar33c8ca92019-01-02 18:00:27 +01002645 inserted_bytes(lnum, curwin->w_cursor.col, -count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646
2647 return OK;
2648}
2649
2650/*
2651 * Delete from cursor to end of line.
2652 * Caller must have prepared for undo.
2653 *
2654 * return FAIL for failure, OK otherwise
2655 */
2656 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002657truncate_line(
2658 int fixpos) /* if TRUE fix the cursor position when done */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659{
2660 char_u *newp;
2661 linenr_T lnum = curwin->w_cursor.lnum;
2662 colnr_T col = curwin->w_cursor.col;
2663
2664 if (col == 0)
2665 newp = vim_strsave((char_u *)"");
2666 else
2667 newp = vim_strnsave(ml_get(lnum), col);
2668
2669 if (newp == NULL)
2670 return FAIL;
2671
2672 ml_replace(lnum, newp, FALSE);
2673
2674 /* mark the buffer as changed and prepare for displaying */
2675 changed_bytes(lnum, curwin->w_cursor.col);
2676
2677 /*
2678 * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
2679 */
2680 if (fixpos && curwin->w_cursor.col > 0)
2681 --curwin->w_cursor.col;
2682
2683 return OK;
2684}
2685
2686/*
2687 * Delete "nlines" lines at the cursor.
2688 * Saves the lines for undo first if "undo" is TRUE.
2689 */
2690 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002691del_lines(
2692 long nlines, /* number of lines to delete */
2693 int undo) /* if TRUE, prepare for undo */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694{
2695 long n;
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002696 linenr_T first = curwin->w_cursor.lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697
2698 if (nlines <= 0)
2699 return;
2700
2701 /* save the deleted lines for undo */
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002702 if (undo && u_savedel(first, nlines) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 return;
2704
2705 for (n = 0; n < nlines; )
2706 {
2707 if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
2708 break;
2709
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002710 ml_delete(first, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 ++n;
2712
2713 /* If we delete the last line in the file, stop */
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002714 if (first > curbuf->b_ml.ml_line_count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 break;
2716 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002718 /* Correct the cursor position before calling deleted_lines_mark(), it may
2719 * trigger a callback to display the cursor. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 curwin->w_cursor.col = 0;
2721 check_cursor_lnum();
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002722
2723 /* adjust marks, mark the buffer as changed and prepare for displaying */
2724 deleted_lines_mark(first, n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725}
2726
2727 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002728gchar_pos(pos_T *pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729{
Bram Moolenaar8ada6aa2017-12-19 21:23:21 +01002730 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731
Bram Moolenaar8ada6aa2017-12-19 21:23:21 +01002732 /* When searching columns is sometimes put at the end of a line. */
2733 if (pos->col == MAXCOL)
2734 return NUL;
2735 ptr = ml_get_pos(pos);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002736 if (has_mbyte)
2737 return (*mb_ptr2char)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738 return (int)*ptr;
2739}
2740
2741 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002742gchar_cursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744 if (has_mbyte)
2745 return (*mb_ptr2char)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 return (int)*ml_get_cursor();
2747}
2748
2749/*
2750 * Write a character at the current cursor position.
2751 * It is directly written into the block.
2752 */
2753 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002754pchar_cursor(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755{
2756 *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE)
2757 + curwin->w_cursor.col) = c;
2758}
2759
Bram Moolenaar071d4272004-06-13 20:20:40 +00002760/*
2761 * When extra == 0: Return TRUE if the cursor is before or on the first
2762 * non-blank in the line.
2763 * When extra == 1: Return TRUE if the cursor is before the first non-blank in
2764 * the line.
2765 */
2766 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002767inindent(int extra)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768{
2769 char_u *ptr;
2770 colnr_T col;
2771
Bram Moolenaar1c465442017-03-12 20:10:05 +01002772 for (col = 0, ptr = ml_get_curline(); VIM_ISWHITE(*ptr); ++col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773 ++ptr;
2774 if (col >= curwin->w_cursor.col + extra)
2775 return TRUE;
2776 else
2777 return FALSE;
2778}
2779
2780/*
2781 * Skip to next part of an option argument: Skip space and comma.
2782 */
2783 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01002784skip_to_option_part(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785{
2786 if (*p == ',')
2787 ++p;
2788 while (*p == ' ')
2789 ++p;
2790 return p;
2791}
2792
2793/*
Bram Moolenaarb0b50882010-07-07 18:26:28 +02002794 * Call this function when something in the current buffer is changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795 *
2796 * Most often called through changed_bytes() and changed_lines(), which also
2797 * mark the area of the display to be redrawn.
Bram Moolenaarb0b50882010-07-07 18:26:28 +02002798 *
2799 * Careful: may trigger autocommands that reload the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800 */
2801 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002802changed(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803{
2804#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar5c6dbcb2017-08-30 22:00:20 +02002805 if (p_imst == IM_ON_THE_SPOT)
2806 {
2807 /* The text of the preediting area is inserted, but this doesn't
2808 * mean a change of the buffer yet. That is delayed until the
2809 * text is committed. (this means preedit becomes empty) */
2810 if (im_is_preediting() && !xim_changed_while_preediting)
2811 return;
2812 xim_changed_while_preediting = FALSE;
2813 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814#endif
2815
2816 if (!curbuf->b_changed)
2817 {
2818 int save_msg_scroll = msg_scroll;
2819
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002820 /* Give a warning about changing a read-only file. This may also
2821 * check-out the file, thus change "curbuf"! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822 change_warning(0);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002823
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 /* Create a swap file if that is wanted.
2825 * Don't do this for "nofile" and "nowrite" buffer types. */
2826 if (curbuf->b_may_swap
2827#ifdef FEAT_QUICKFIX
2828 && !bt_dontwrite(curbuf)
2829#endif
2830 )
2831 {
Bram Moolenaarb01f3572016-01-15 15:17:04 +01002832 int save_need_wait_return = need_wait_return;
2833
2834 need_wait_return = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 ml_open_file(curbuf);
2836
2837 /* The ml_open_file() can cause an ATTENTION message.
2838 * Wait two seconds, to make sure the user reads this unexpected
2839 * message. Since we could be anywhere, call wait_return() now,
2840 * and don't let the emsg() set msg_scroll. */
2841 if (need_wait_return && emsg_silent == 0)
2842 {
2843 out_flush();
2844 ui_delay(2000L, TRUE);
2845 wait_return(TRUE);
2846 msg_scroll = save_msg_scroll;
2847 }
Bram Moolenaarb01f3572016-01-15 15:17:04 +01002848 else
2849 need_wait_return = save_need_wait_return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850 }
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02002851 changed_int();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852 }
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002853 ++CHANGEDTICK(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854}
2855
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02002856/*
2857 * Internal part of changed(), no user interaction.
2858 */
2859 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002860changed_int(void)
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02002861{
2862 curbuf->b_changed = TRUE;
2863 ml_setflags(curbuf);
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02002864 check_status(curbuf);
2865 redraw_tabline = TRUE;
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02002866#ifdef FEAT_TITLE
2867 need_maketitle = TRUE; /* set window title later */
2868#endif
2869}
2870
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01002871static void changedOneline(buf_T *buf, linenr_T lnum);
2872static void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra);
2873static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874
2875/*
2876 * Changed bytes within a single line for the current buffer.
2877 * - marks the windows on this buffer to be redisplayed
2878 * - marks the buffer changed by calling changed()
2879 * - invalidates cached values
Bram Moolenaarb0b50882010-07-07 18:26:28 +02002880 * Careful: may trigger autocommands that reload the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 */
2882 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002883changed_bytes(linenr_T lnum, colnr_T col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884{
Bram Moolenaardba8a912005-04-24 22:08:39 +00002885 changedOneline(curbuf, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886 changed_common(lnum, col, lnum + 1, 0L);
Bram Moolenaardba8a912005-04-24 22:08:39 +00002887
2888#ifdef FEAT_DIFF
2889 /* Diff highlighting in other diff windows may need to be updated too. */
2890 if (curwin->w_p_diff)
2891 {
2892 win_T *wp;
2893 linenr_T wlnum;
2894
Bram Moolenaar29323592016-07-24 22:04:11 +02002895 FOR_ALL_WINDOWS(wp)
Bram Moolenaardba8a912005-04-24 22:08:39 +00002896 if (wp->w_p_diff && wp != curwin)
2897 {
2898 redraw_win_later(wp, VALID);
2899 wlnum = diff_lnum_win(lnum, wp);
2900 if (wlnum > 0)
2901 changedOneline(wp->w_buffer, wlnum);
2902 }
2903 }
2904#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905}
2906
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002907/*
2908 * Like changed_bytes() but also adjust text properties for "added" bytes.
2909 * When "added" is negative text was deleted.
2910 */
2911 void
Bram Moolenaar402385a2019-01-11 14:10:03 +01002912inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED)
Bram Moolenaar44746aa2019-01-02 00:02:11 +01002913{
2914 changed_bytes(lnum, col);
2915
2916#ifdef FEAT_TEXT_PROP
2917 if (curbuf->b_has_textprop && added != 0)
2918 adjust_prop_columns(lnum, col, added);
2919#endif
2920}
2921
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002923changedOneline(buf_T *buf, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924{
Bram Moolenaardba8a912005-04-24 22:08:39 +00002925 if (buf->b_mod_set)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 {
2927 /* find the maximum area that must be redisplayed */
Bram Moolenaardba8a912005-04-24 22:08:39 +00002928 if (lnum < buf->b_mod_top)
2929 buf->b_mod_top = lnum;
2930 else if (lnum >= buf->b_mod_bot)
2931 buf->b_mod_bot = lnum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 }
2933 else
2934 {
2935 /* set the area that must be redisplayed to one line */
Bram Moolenaardba8a912005-04-24 22:08:39 +00002936 buf->b_mod_set = TRUE;
2937 buf->b_mod_top = lnum;
2938 buf->b_mod_bot = lnum + 1;
2939 buf->b_mod_xlines = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 }
2941}
2942
2943/*
2944 * Appended "count" lines below line "lnum" in the current buffer.
2945 * Must be called AFTER the change and after mark_adjust().
2946 * Takes care of marking the buffer to be redrawn and sets the changed flag.
2947 */
2948 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002949appended_lines(linenr_T lnum, long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950{
2951 changed_lines(lnum + 1, 0, lnum + 1, count);
2952}
2953
2954/*
2955 * Like appended_lines(), but adjust marks first.
2956 */
2957 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002958appended_lines_mark(linenr_T lnum, long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959{
Bram Moolenaar82faa252016-06-04 20:14:07 +02002960 /* Skip mark_adjust when adding a line after the last one, there can't
Bram Moolenaarf58a8472017-03-05 18:03:04 +01002961 * be marks there. But it's still needed in diff mode. */
2962 if (lnum + count < curbuf->b_ml.ml_line_count
2963#ifdef FEAT_DIFF
2964 || curwin->w_p_diff
2965#endif
2966 )
Bram Moolenaar82faa252016-06-04 20:14:07 +02002967 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002968 changed_lines(lnum + 1, 0, lnum + 1, count);
2969}
2970
2971/*
2972 * Deleted "count" lines at line "lnum" in the current buffer.
2973 * Must be called AFTER the change and after mark_adjust().
2974 * Takes care of marking the buffer to be redrawn and sets the changed flag.
2975 */
2976 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002977deleted_lines(linenr_T lnum, long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978{
2979 changed_lines(lnum, 0, lnum + count, -count);
2980}
2981
2982/*
2983 * Like deleted_lines(), but adjust marks first.
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002984 * Make sure the cursor is on a valid line before calling, a GUI callback may
2985 * be triggered to display the cursor.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 */
2987 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002988deleted_lines_mark(linenr_T lnum, long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989{
2990 mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count);
2991 changed_lines(lnum, 0, lnum + count, -count);
2992}
2993
2994/*
2995 * Changed lines for the current buffer.
2996 * Must be called AFTER the change and after mark_adjust().
2997 * - mark the buffer changed by calling changed()
2998 * - mark the windows on this buffer to be redisplayed
2999 * - invalidate cached values
3000 * "lnum" is the first line that needs displaying, "lnume" the first line
3001 * below the changed lines (BEFORE the change).
3002 * When only inserting lines, "lnum" and "lnume" are equal.
3003 * Takes care of calling changed() and updating b_mod_*.
Bram Moolenaarb0b50882010-07-07 18:26:28 +02003004 * Careful: may trigger autocommands that reload the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005 */
3006 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003007changed_lines(
3008 linenr_T lnum, /* first line with change */
3009 colnr_T col, /* column in first line with change */
3010 linenr_T lnume, /* line below last changed line */
3011 long xtra) /* number of extra lines (negative when deleting) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012{
Bram Moolenaardba8a912005-04-24 22:08:39 +00003013 changed_lines_buf(curbuf, lnum, lnume, xtra);
3014
3015#ifdef FEAT_DIFF
Bram Moolenaare3521d92018-09-16 14:10:31 +02003016 if (xtra == 0 && curwin->w_p_diff && !diff_internal())
Bram Moolenaardba8a912005-04-24 22:08:39 +00003017 {
3018 /* When the number of lines doesn't change then mark_adjust() isn't
3019 * called and other diff buffers still need to be marked for
3020 * displaying. */
3021 win_T *wp;
3022 linenr_T wlnum;
3023
Bram Moolenaar29323592016-07-24 22:04:11 +02003024 FOR_ALL_WINDOWS(wp)
Bram Moolenaardba8a912005-04-24 22:08:39 +00003025 if (wp->w_p_diff && wp != curwin)
3026 {
3027 redraw_win_later(wp, VALID);
3028 wlnum = diff_lnum_win(lnum, wp);
3029 if (wlnum > 0)
3030 changed_lines_buf(wp->w_buffer, wlnum,
3031 lnume - lnum + wlnum, 0L);
3032 }
3033 }
3034#endif
3035
3036 changed_common(lnum, col, lnume, xtra);
3037}
3038
3039 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003040changed_lines_buf(
3041 buf_T *buf,
3042 linenr_T lnum, /* first line with change */
3043 linenr_T lnume, /* line below last changed line */
3044 long xtra) /* number of extra lines (negative when deleting) */
Bram Moolenaardba8a912005-04-24 22:08:39 +00003045{
3046 if (buf->b_mod_set)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047 {
3048 /* find the maximum area that must be redisplayed */
Bram Moolenaardba8a912005-04-24 22:08:39 +00003049 if (lnum < buf->b_mod_top)
3050 buf->b_mod_top = lnum;
3051 if (lnum < buf->b_mod_bot)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052 {
3053 /* adjust old bot position for xtra lines */
Bram Moolenaardba8a912005-04-24 22:08:39 +00003054 buf->b_mod_bot += xtra;
3055 if (buf->b_mod_bot < lnum)
3056 buf->b_mod_bot = lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 }
Bram Moolenaardba8a912005-04-24 22:08:39 +00003058 if (lnume + xtra > buf->b_mod_bot)
3059 buf->b_mod_bot = lnume + xtra;
3060 buf->b_mod_xlines += xtra;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 }
3062 else
3063 {
3064 /* set the area that must be redisplayed */
Bram Moolenaardba8a912005-04-24 22:08:39 +00003065 buf->b_mod_set = TRUE;
3066 buf->b_mod_top = lnum;
3067 buf->b_mod_bot = lnume + xtra;
3068 buf->b_mod_xlines = xtra;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070}
3071
Bram Moolenaarb0b50882010-07-07 18:26:28 +02003072/*
3073 * Common code for when a change is was made.
3074 * See changed_lines() for the arguments.
3075 * Careful: may trigger autocommands that reload the buffer.
3076 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003078changed_common(
3079 linenr_T lnum,
3080 colnr_T col,
3081 linenr_T lnume,
3082 long xtra)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083{
3084 win_T *wp;
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00003085 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086 int i;
3087#ifdef FEAT_JUMPLIST
3088 int cols;
3089 pos_T *p;
3090 int add;
3091#endif
3092
3093 /* mark the buffer as modified */
3094 changed();
3095
Bram Moolenaare3521d92018-09-16 14:10:31 +02003096#ifdef FEAT_DIFF
3097 if (curwin->w_p_diff && diff_internal())
3098 curtab->tp_diff_update = TRUE;
3099#endif
3100
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 /* set the '. mark */
3102 if (!cmdmod.keepjumps)
3103 {
3104 curbuf->b_last_change.lnum = lnum;
3105 curbuf->b_last_change.col = col;
3106
3107#ifdef FEAT_JUMPLIST
3108 /* Create a new entry if a new undo-able change was started or we
3109 * don't have an entry yet. */
3110 if (curbuf->b_new_change || curbuf->b_changelistlen == 0)
3111 {
3112 if (curbuf->b_changelistlen == 0)
3113 add = TRUE;
3114 else
3115 {
3116 /* Don't create a new entry when the line number is the same
3117 * as the last one and the column is not too far away. Avoids
3118 * creating many entries for typing "xxxxx". */
3119 p = &curbuf->b_changelist[curbuf->b_changelistlen - 1];
3120 if (p->lnum != lnum)
3121 add = TRUE;
3122 else
3123 {
3124 cols = comp_textwidth(FALSE);
3125 if (cols == 0)
3126 cols = 79;
3127 add = (p->col + cols < col || col + cols < p->col);
3128 }
3129 }
3130 if (add)
3131 {
3132 /* This is the first of a new sequence of undo-able changes
3133 * and it's at some distance of the last change. Use a new
3134 * position in the changelist. */
3135 curbuf->b_new_change = FALSE;
3136
3137 if (curbuf->b_changelistlen == JUMPLISTSIZE)
3138 {
3139 /* changelist is full: remove oldest entry */
3140 curbuf->b_changelistlen = JUMPLISTSIZE - 1;
3141 mch_memmove(curbuf->b_changelist, curbuf->b_changelist + 1,
3142 sizeof(pos_T) * (JUMPLISTSIZE - 1));
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00003143 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144 {
3145 /* Correct position in changelist for other windows on
3146 * this buffer. */
3147 if (wp->w_buffer == curbuf && wp->w_changelistidx > 0)
3148 --wp->w_changelistidx;
3149 }
3150 }
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00003151 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 {
3153 /* For other windows, if the position in the changelist is
3154 * at the end it stays at the end. */
3155 if (wp->w_buffer == curbuf
3156 && wp->w_changelistidx == curbuf->b_changelistlen)
3157 ++wp->w_changelistidx;
3158 }
3159 ++curbuf->b_changelistlen;
3160 }
3161 }
3162 curbuf->b_changelist[curbuf->b_changelistlen - 1] =
3163 curbuf->b_last_change;
3164 /* The current window is always after the last change, so that "g,"
3165 * takes you back to it. */
3166 curwin->w_changelistidx = curbuf->b_changelistlen;
3167#endif
3168 }
3169
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00003170 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171 {
3172 if (wp->w_buffer == curbuf)
3173 {
3174 /* Mark this window to be redrawn later. */
3175 if (wp->w_redr_type < VALID)
3176 wp->w_redr_type = VALID;
3177
3178 /* Check if a change in the buffer has invalidated the cached
3179 * values for the cursor. */
3180#ifdef FEAT_FOLDING
3181 /*
3182 * Update the folds for this window. Can't postpone this, because
3183 * a following operator might work on the whole fold: ">>dd".
3184 */
3185 foldUpdate(wp, lnum, lnume + xtra - 1);
3186
3187 /* The change may cause lines above or below the change to become
3188 * included in a fold. Set lnum/lnume to the first/last line that
3189 * might be displayed differently.
3190 * Set w_cline_folded here as an efficient way to update it when
3191 * inserting lines just above a closed fold. */
3192 i = hasFoldingWin(wp, lnum, &lnum, NULL, FALSE, NULL);
3193 if (wp->w_cursor.lnum == lnum)
3194 wp->w_cline_folded = i;
3195 i = hasFoldingWin(wp, lnume, NULL, &lnume, FALSE, NULL);
3196 if (wp->w_cursor.lnum == lnume)
3197 wp->w_cline_folded = i;
3198
3199 /* If the changed line is in a range of previously folded lines,
3200 * compare with the first line in that range. */
3201 if (wp->w_cursor.lnum <= lnum)
3202 {
3203 i = find_wl_entry(wp, lnum);
3204 if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum)
3205 changed_line_abv_curs_win(wp);
3206 }
3207#endif
3208
3209 if (wp->w_cursor.lnum > lnum)
3210 changed_line_abv_curs_win(wp);
3211 else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col)
3212 changed_cline_bef_curs_win(wp);
3213 if (wp->w_botline >= lnum)
3214 {
3215 /* Assume that botline doesn't change (inserted lines make
3216 * other lines scroll down below botline). */
3217 approximate_botline_win(wp);
3218 }
3219
3220 /* Check if any w_lines[] entries have become invalid.
3221 * For entries below the change: Correct the lnums for
3222 * inserted/deleted lines. Makes it possible to stop displaying
3223 * after the change. */
3224 for (i = 0; i < wp->w_lines_valid; ++i)
3225 if (wp->w_lines[i].wl_valid)
3226 {
3227 if (wp->w_lines[i].wl_lnum >= lnum)
3228 {
3229 if (wp->w_lines[i].wl_lnum < lnume)
3230 {
3231 /* line included in change */
3232 wp->w_lines[i].wl_valid = FALSE;
3233 }
3234 else if (xtra != 0)
3235 {
3236 /* line below change */
3237 wp->w_lines[i].wl_lnum += xtra;
3238#ifdef FEAT_FOLDING
3239 wp->w_lines[i].wl_lastlnum += xtra;
3240#endif
3241 }
3242 }
3243#ifdef FEAT_FOLDING
3244 else if (wp->w_lines[i].wl_lastlnum >= lnum)
3245 {
3246 /* change somewhere inside this range of folded lines,
3247 * may need to be redrawn */
3248 wp->w_lines[i].wl_valid = FALSE;
3249 }
3250#endif
3251 }
Bram Moolenaar3234cc62009-11-03 17:47:12 +00003252
3253#ifdef FEAT_FOLDING
3254 /* Take care of side effects for setting w_topline when folds have
3255 * changed. Esp. when the buffer was changed in another window. */
3256 if (hasAnyFolding(wp))
3257 set_topline(wp, wp->w_topline);
3258#endif
Bram Moolenaarfd859c92014-05-13 12:44:24 +02003259 /* relative numbering may require updating more */
3260 if (wp->w_p_rnu)
3261 redraw_win_later(wp, SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262 }
3263 }
3264
3265 /* Call update_screen() later, which checks out what needs to be redrawn,
3266 * since it notices b_mod_set and then uses b_mod_*. */
3267 if (must_redraw < VALID)
3268 must_redraw = VALID;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003269
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003270 /* when the cursor line is changed always trigger CursorMoved */
Bram Moolenaare163f1c2006-10-17 09:12:21 +00003271 if (lnum <= curwin->w_cursor.lnum
3272 && lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum)
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003273 last_cursormoved.lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274}
3275
3276/*
3277 * unchanged() is called when the changed flag must be reset for buffer 'buf'
3278 */
3279 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003280unchanged(
3281 buf_T *buf,
3282 int ff) /* also reset 'fileformat' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283{
Bram Moolenaar164c60f2011-01-22 00:11:50 +01003284 if (buf->b_changed || (ff && file_ff_differs(buf, FALSE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285 {
3286 buf->b_changed = 0;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003287 ml_setflags(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 if (ff)
3289 save_file_ff(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290 check_status(buf);
Bram Moolenaar997fb4b2006-02-17 21:53:23 +00003291 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292#ifdef FEAT_TITLE
3293 need_maketitle = TRUE; /* set window title later */
3294#endif
3295 }
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003296 ++CHANGEDTICK(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297#ifdef FEAT_NETBEANS_INTG
3298 netbeans_unmodified(buf);
3299#endif
3300}
3301
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302/*
3303 * check_status: called when the status bars for the buffer 'buf'
3304 * need to be updated
3305 */
3306 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003307check_status(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003308{
3309 win_T *wp;
3310
Bram Moolenaar29323592016-07-24 22:04:11 +02003311 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312 if (wp->w_buffer == buf && wp->w_status_height)
3313 {
3314 wp->w_redr_status = TRUE;
3315 if (must_redraw < VALID)
3316 must_redraw = VALID;
3317 }
3318}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319
3320/*
3321 * If the file is readonly, give a warning message with the first change.
3322 * Don't do this for autocommands.
3323 * Don't use emsg(), because it flushes the macro buffer.
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +00003324 * If we have undone all changes b_changed will be FALSE, but "b_did_warn"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 * will be TRUE.
Bram Moolenaarb0b50882010-07-07 18:26:28 +02003326 * Careful: may trigger autocommands that reload the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327 */
3328 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003329change_warning(
3330 int col) /* column for message; non-zero when in insert
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 mode and 'showmode' is on */
3332{
Bram Moolenaar496c5262009-03-18 14:42:00 +00003333 static char *w_readonly = N_("W10: Warning: Changing a readonly file");
3334
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 if (curbuf->b_did_warn == FALSE
3336 && curbufIsChanged() == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 && !autocmd_busy
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 && curbuf->b_p_ro)
3339 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003340 ++curbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, FALSE, curbuf);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003342 --curbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 if (!curbuf->b_p_ro)
3344 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 /*
3346 * Do what msg() does, but with a column offset if the warning should
3347 * be after the mode message.
3348 */
3349 msg_start();
3350 if (msg_row == Rows - 1)
3351 msg_col = col;
Bram Moolenaar8820b482017-03-16 17:23:31 +01003352 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01003353 msg_puts_attr(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
Bram Moolenaar496c5262009-03-18 14:42:00 +00003354#ifdef FEAT_EVAL
3355 set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_readonly), -1);
3356#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357 msg_clr_eos();
3358 (void)msg_end();
Bram Moolenaare5f2a072017-02-01 22:31:49 +01003359 if (msg_silent == 0 && !silent_mode
3360#ifdef FEAT_EVAL
3361 && time_for_testing != 1
3362#endif
3363 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364 {
3365 out_flush();
3366 ui_delay(1000L, TRUE); /* give the user time to think about it */
3367 }
3368 curbuf->b_did_warn = TRUE;
3369 redraw_cmdline = FALSE; /* don't redraw and erase the message */
3370 if (msg_row < Rows - 1)
3371 showmode();
3372 }
3373}
3374
3375/*
3376 * Ask for a reply from the user, a 'y' or a 'n'.
3377 * No other characters are accepted, the message is repeated until a valid
3378 * reply is entered or CTRL-C is hit.
3379 * If direct is TRUE, don't use vgetc() but ui_inchar(), don't get characters
3380 * from any buffers but directly from the user.
3381 *
3382 * return the 'y' or 'n'
3383 */
3384 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01003385ask_yesno(char_u *str, int direct)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003386{
3387 int r = ' ';
3388 int save_State = State;
3389
3390 if (exiting) /* put terminal in raw mode for this question */
3391 settmode(TMODE_RAW);
3392 ++no_wait_return;
3393#ifdef USE_ON_FLY_SCROLL
3394 dont_scroll = TRUE; /* disallow scrolling here */
3395#endif
3396 State = CONFIRM; /* mouse behaves like with :confirm */
3397#ifdef FEAT_MOUSE
3398 setmouse(); /* disables mouse for xterm */
3399#endif
3400 ++no_mapping;
3401 ++allow_keys; /* no mapping here, but recognize keys */
3402
3403 while (r != 'y' && r != 'n')
3404 {
3405 /* same highlighting as for wait_return */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003406 smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407 if (direct)
3408 r = get_keystroke();
3409 else
Bram Moolenaar913626c2008-01-03 11:43:42 +00003410 r = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003411 if (r == Ctrl_C || r == ESC)
3412 r = 'n';
3413 msg_putchar(r); /* show what you typed */
3414 out_flush();
3415 }
3416 --no_wait_return;
3417 State = save_State;
3418#ifdef FEAT_MOUSE
3419 setmouse();
3420#endif
3421 --no_mapping;
3422 --allow_keys;
3423
3424 return r;
3425}
3426
Bram Moolenaar2526ef22013-03-16 14:20:51 +01003427#if defined(FEAT_MOUSE) || defined(PROTO)
3428/*
3429 * Return TRUE if "c" is a mouse key.
3430 */
3431 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01003432is_mouse_key(int c)
Bram Moolenaar2526ef22013-03-16 14:20:51 +01003433{
3434 return c == K_LEFTMOUSE
3435 || c == K_LEFTMOUSE_NM
3436 || c == K_LEFTDRAG
3437 || c == K_LEFTRELEASE
3438 || c == K_LEFTRELEASE_NM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003439 || c == K_MOUSEMOVE
Bram Moolenaar2526ef22013-03-16 14:20:51 +01003440 || c == K_MIDDLEMOUSE
3441 || c == K_MIDDLEDRAG
3442 || c == K_MIDDLERELEASE
3443 || c == K_RIGHTMOUSE
3444 || c == K_RIGHTDRAG
3445 || c == K_RIGHTRELEASE
3446 || c == K_MOUSEDOWN
3447 || c == K_MOUSEUP
3448 || c == K_MOUSELEFT
3449 || c == K_MOUSERIGHT
3450 || c == K_X1MOUSE
3451 || c == K_X1DRAG
3452 || c == K_X1RELEASE
3453 || c == K_X2MOUSE
3454 || c == K_X2DRAG
3455 || c == K_X2RELEASE;
3456}
3457#endif
3458
Bram Moolenaar071d4272004-06-13 20:20:40 +00003459/*
3460 * Get a key stroke directly from the user.
3461 * Ignores mouse clicks and scrollbar events, except a click for the left
3462 * button (used at the more prompt).
3463 * Doesn't use vgetc(), because it syncs undo and eats mapped characters.
3464 * Disadvantage: typeahead is ignored.
3465 * Translates the interrupt character for unix to ESC.
3466 */
3467 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01003468get_keystroke(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469{
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003470 char_u *buf = NULL;
3471 int buflen = 150;
3472 int maxlen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473 int len = 0;
3474 int n;
3475 int save_mapped_ctrl_c = mapped_ctrl_c;
Bram Moolenaar4395a712006-09-05 18:57:57 +00003476 int waited = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003477
3478 mapped_ctrl_c = FALSE; /* mappings are not used here */
3479 for (;;)
3480 {
3481 cursor_on();
3482 out_flush();
3483
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003484 /* Leave some room for check_termcode() to insert a key code into (max
3485 * 5 chars plus NUL). And fix_input_buffer() can triple the number of
3486 * bytes. */
3487 maxlen = (buflen - 6 - len) / 3;
3488 if (buf == NULL)
3489 buf = alloc(buflen);
3490 else if (maxlen < 10)
3491 {
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01003492 char_u *t_buf = buf;
3493
Bram Moolenaardc7e85e2012-06-20 12:40:08 +02003494 /* Need some more space. This might happen when receiving a long
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003495 * escape sequence. */
3496 buflen += 100;
3497 buf = vim_realloc(buf, buflen);
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01003498 if (buf == NULL)
3499 vim_free(t_buf);
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003500 maxlen = (buflen - 6 - len) / 3;
3501 }
3502 if (buf == NULL)
3503 {
3504 do_outofmem_msg((long_u)buflen);
3505 return ESC; /* panic! */
3506 }
3507
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508 /* First time: blocking wait. Second time: wait up to 100ms for a
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003509 * terminal code to complete. */
3510 n = ui_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511 if (n > 0)
3512 {
3513 /* Replace zero and CSI by a special key code. */
Bram Moolenaar6bff02e2016-08-16 22:50:55 +02003514 n = fix_input_buffer(buf + len, n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003515 len += n;
Bram Moolenaar4395a712006-09-05 18:57:57 +00003516 waited = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003517 }
Bram Moolenaar4395a712006-09-05 18:57:57 +00003518 else if (len > 0)
3519 ++waited; /* keep track of the waiting time */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520
Bram Moolenaar4395a712006-09-05 18:57:57 +00003521 /* Incomplete termcode and not timed out yet: get more characters */
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003522 if ((n = check_termcode(1, buf, buflen, &len)) < 0
Bram Moolenaar4395a712006-09-05 18:57:57 +00003523 && (!p_ttimeout || waited * 100L < (p_ttm < 0 ? p_tm : p_ttm)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 continue;
Bram Moolenaar4395a712006-09-05 18:57:57 +00003525
Bram Moolenaar946ffd42010-12-30 12:30:31 +01003526 if (n == KEYLEN_REMOVED) /* key code removed */
Bram Moolenaar6eb634e2011-03-03 15:04:08 +01003527 {
Bram Moolenaarfd30cd42011-03-22 13:07:26 +01003528 if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0)
Bram Moolenaar6eb634e2011-03-03 15:04:08 +01003529 {
3530 /* Redrawing was postponed, do it now. */
3531 update_screen(0);
3532 setcursor(); /* put cursor back where it belongs */
3533 }
Bram Moolenaar946ffd42010-12-30 12:30:31 +01003534 continue;
Bram Moolenaar6eb634e2011-03-03 15:04:08 +01003535 }
Bram Moolenaar946ffd42010-12-30 12:30:31 +01003536 if (n > 0) /* found a termcode: adjust length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537 len = n;
Bram Moolenaar946ffd42010-12-30 12:30:31 +01003538 if (len == 0) /* nothing typed yet */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539 continue;
3540
3541 /* Handle modifier and/or special key code. */
3542 n = buf[0];
3543 if (n == K_SPECIAL)
3544 {
3545 n = TO_SPECIAL(buf[1], buf[2]);
3546 if (buf[1] == KS_MODIFIER
3547 || n == K_IGNORE
Bram Moolenaara5be25e2013-03-16 21:35:33 +01003548#ifdef FEAT_MOUSE
Bram Moolenaar2526ef22013-03-16 14:20:51 +01003549 || (is_mouse_key(n) && n != K_LEFTMOUSE)
Bram Moolenaara5be25e2013-03-16 21:35:33 +01003550#endif
Bram Moolenaar2526ef22013-03-16 14:20:51 +01003551#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 || n == K_VER_SCROLLBAR
3553 || n == K_HOR_SCROLLBAR
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554#endif
3555 )
3556 {
3557 if (buf[1] == KS_MODIFIER)
3558 mod_mask = buf[2];
3559 len -= 3;
3560 if (len > 0)
3561 mch_memmove(buf, buf + 3, (size_t)len);
3562 continue;
3563 }
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00003564 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566 if (has_mbyte)
3567 {
3568 if (MB_BYTE2LEN(n) > len)
3569 continue; /* more bytes to get */
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003570 buf[len >= buflen ? buflen - 1 : len] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571 n = (*mb_ptr2char)(buf);
3572 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573#ifdef UNIX
3574 if (n == intr_char)
3575 n = ESC;
3576#endif
3577 break;
3578 }
Bram Moolenaara8c8a682012-02-05 22:05:48 +01003579 vim_free(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003580
3581 mapped_ctrl_c = save_mapped_ctrl_c;
3582 return n;
3583}
3584
3585/*
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00003586 * Get a number from the user.
3587 * When "mouse_used" is not NULL allow using the mouse.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 */
3589 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01003590get_number(
3591 int colon, /* allow colon to abort */
3592 int *mouse_used)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593{
3594 int n = 0;
3595 int c;
Bram Moolenaar3991dab2006-03-27 17:01:56 +00003596 int typed = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00003598 if (mouse_used != NULL)
3599 *mouse_used = FALSE;
3600
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 /* When not printing messages, the user won't know what to type, return a
3602 * zero (as if CR was hit). */
3603 if (msg_silent != 0)
3604 return 0;
3605
3606#ifdef USE_ON_FLY_SCROLL
3607 dont_scroll = TRUE; /* disallow scrolling here */
3608#endif
3609 ++no_mapping;
3610 ++allow_keys; /* no mapping here, but recognize keys */
3611 for (;;)
3612 {
3613 windgoto(msg_row, msg_col);
3614 c = safe_vgetc();
3615 if (VIM_ISDIGIT(c))
3616 {
3617 n = n * 10 + c - '0';
3618 msg_putchar(c);
Bram Moolenaar3991dab2006-03-27 17:01:56 +00003619 ++typed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620 }
3621 else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H)
3622 {
Bram Moolenaar3991dab2006-03-27 17:01:56 +00003623 if (typed > 0)
3624 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01003625 msg_puts("\b \b");
Bram Moolenaar3991dab2006-03-27 17:01:56 +00003626 --typed;
3627 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628 n /= 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003629 }
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00003630#ifdef FEAT_MOUSE
3631 else if (mouse_used != NULL && c == K_LEFTMOUSE)
3632 {
3633 *mouse_used = TRUE;
3634 n = mouse_row + 1;
3635 break;
3636 }
3637#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638 else if (n == 0 && c == ':' && colon)
3639 {
3640 stuffcharReadbuff(':');
3641 if (!exmode_active)
3642 cmdline_row = msg_row;
3643 skip_redraw = TRUE; /* skip redraw once */
3644 do_redraw = FALSE;
3645 break;
3646 }
3647 else if (c == CAR || c == NL || c == Ctrl_C || c == ESC)
3648 break;
3649 }
3650 --no_mapping;
3651 --allow_keys;
3652 return n;
3653}
3654
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003655/*
3656 * Ask the user to enter a number.
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00003657 * When "mouse_used" is not NULL allow using the mouse and in that case return
3658 * the line number.
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003659 */
3660 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01003661prompt_for_number(int *mouse_used)
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003662{
3663 int i;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003664 int save_cmdline_row;
3665 int save_State;
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003666
3667 /* When using ":silent" assume that <CR> was entered. */
Bram Moolenaar42eeac32005-06-29 22:40:58 +00003668 if (mouse_used != NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01003669 msg_puts(_("Type number and <Enter> or click with mouse (empty cancels): "));
Bram Moolenaar42eeac32005-06-29 22:40:58 +00003670 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01003671 msg_puts(_("Type number and <Enter> (empty cancels): "));
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003672
Bram Moolenaar4cbdf152018-08-26 21:23:07 +02003673 // Set the state such that text can be selected/copied/pasted and we still
3674 // get mouse events. redraw_after_callback() will not redraw if cmdline_row
3675 // is zero.
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003676 save_cmdline_row = cmdline_row;
Bram Moolenaar203335e2006-09-03 14:35:42 +00003677 cmdline_row = 0;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003678 save_State = State;
Bram Moolenaar4cbdf152018-08-26 21:23:07 +02003679 State = CMDLINE;
Bram Moolenaar73658312018-04-24 17:41:57 +02003680#ifdef FEAT_MOUSE
Bram Moolenaar4cbdf152018-08-26 21:23:07 +02003681 // May show different mouse shape.
Bram Moolenaar73658312018-04-24 17:41:57 +02003682 setmouse();
3683#endif
3684
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00003685 i = get_number(TRUE, mouse_used);
3686 if (KeyTyped)
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003687 {
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00003688 /* don't call wait_return() now */
3689 /* msg_putchar('\n'); */
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003690 cmdline_row = msg_row - 1;
3691 need_wait_return = FALSE;
3692 msg_didany = FALSE;
Bram Moolenaarb2450162009-07-22 09:04:20 +00003693 msg_didout = FALSE;
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003694 }
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003695 else
3696 cmdline_row = save_cmdline_row;
3697 State = save_State;
Bram Moolenaar73658312018-04-24 17:41:57 +02003698#ifdef FEAT_MOUSE
Bram Moolenaar4cbdf152018-08-26 21:23:07 +02003699 // May need to restore mouse shape.
Bram Moolenaar73658312018-04-24 17:41:57 +02003700 setmouse();
3701#endif
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003702
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00003703 return i;
3704}
3705
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003707msgmore(long n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708{
3709 long pn;
3710
3711 if (global_busy /* no messages now, wait until global is finished */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712 || !messaging()) /* 'lazyredraw' set, don't do messages now */
3713 return;
3714
Bram Moolenaar7df2d662005-01-25 22:18:08 +00003715 /* We don't want to overwrite another important message, but do overwrite
3716 * a previous "more lines" or "fewer lines" message, so that "5dd" and
3717 * then "put" reports the last action. */
3718 if (keep_msg != NULL && !keep_msg_more)
3719 return;
3720
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721 if (n > 0)
3722 pn = n;
3723 else
3724 pn = -n;
3725
3726 if (pn > p_report)
3727 {
Bram Moolenaarda6e8912018-08-21 15:12:14 +02003728 if (n > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01003729 vim_snprintf(msg_buf, MSG_BUF_LEN,
Bram Moolenaarda6e8912018-08-21 15:12:14 +02003730 NGETTEXT("%ld more line", "%ld more lines", pn), pn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01003732 vim_snprintf(msg_buf, MSG_BUF_LEN,
Bram Moolenaarda6e8912018-08-21 15:12:14 +02003733 NGETTEXT("%ld line less", "%ld fewer lines", pn), pn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734 if (got_int)
Bram Moolenaar32526b32019-01-19 17:43:09 +01003735 vim_strcat((char_u *)msg_buf, (char_u *)_(" (Interrupted)"),
3736 MSG_BUF_LEN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 if (msg(msg_buf))
3738 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01003739 set_keep_msg((char_u *)msg_buf, 0);
Bram Moolenaar7df2d662005-01-25 22:18:08 +00003740 keep_msg_more = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741 }
3742 }
3743}
3744
3745/*
3746 * flush map and typeahead buffers and give a warning for an error
3747 */
3748 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003749beep_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750{
3751 if (emsg_silent == 0)
3752 {
Bram Moolenaar6a2633b2018-10-07 23:16:36 +02003753 flush_buffers(FLUSH_MINIMAL);
Bram Moolenaar165bc692015-07-21 17:53:25 +02003754 vim_beep(BO_ERROR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 }
3756}
3757
3758/*
Bram Moolenaar165bc692015-07-21 17:53:25 +02003759 * Give a warning for an error.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760 */
3761 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003762vim_beep(
3763 unsigned val) /* one of the BO_ values, e.g., BO_OPER */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764{
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01003765#ifdef FEAT_EVAL
3766 called_vim_beep = TRUE;
3767#endif
3768
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769 if (emsg_silent == 0)
3770 {
Bram Moolenaar165bc692015-07-21 17:53:25 +02003771 if (!((bo_flags & val) || (bo_flags & BO_ALL)))
3772 {
Bram Moolenaar2e147ca2017-06-27 17:09:37 +02003773#ifdef ELAPSED_FUNC
3774 static int did_init = FALSE;
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01003775 static elapsed_T start_tv;
Bram Moolenaar2e147ca2017-06-27 17:09:37 +02003776
3777 /* Only beep once per half a second, otherwise a sequence of beeps
3778 * would freeze Vim. */
3779 if (!did_init || ELAPSED_FUNC(start_tv) > 500)
3780 {
3781 did_init = TRUE;
3782 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783#endif
Bram Moolenaar2e147ca2017-06-27 17:09:37 +02003784 if (p_vb
3785#ifdef FEAT_GUI
3786 /* While the GUI is starting up the termcap is set for
3787 * the GUI but the output still goes to a terminal. */
3788 && !(gui.in_use && gui.starting)
3789#endif
3790 )
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003791 {
Bram Moolenaar2e147ca2017-06-27 17:09:37 +02003792 out_str_cf(T_VB);
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003793#ifdef FEAT_VTP
3794 /* No restore color information, refresh the screen. */
3795 if (has_vtp_working() != 0
3796# ifdef FEAT_TERMGUICOLORS
Bram Moolenaarc5cd8852018-05-01 15:47:38 +02003797 && (p_tgc || (!p_tgc && t_colors >= 256))
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003798# endif
3799 )
3800 {
3801 redraw_later(CLEAR);
3802 update_screen(0);
3803 redrawcmd();
3804 }
3805#endif
3806 }
Bram Moolenaar2e147ca2017-06-27 17:09:37 +02003807 else
3808 out_char(BELL);
3809#ifdef ELAPSED_FUNC
3810 }
3811#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 }
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003813
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01003814 /* When 'debug' contains "beep" produce a message. If we are sourcing
3815 * a script or executing a function give the user a hint where the beep
3816 * comes from. */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003817 if (vim_strchr(p_debug, 'e') != NULL)
3818 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003819 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01003820 msg_attr(_("Beep!"), HL_ATTR(HLF_W));
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00003821 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 }
3823}
3824
3825/*
3826 * To get the "real" home directory:
3827 * - get value of $HOME
3828 * For Unix:
3829 * - go to that directory
3830 * - do mch_dirname() to get the real name of that directory.
3831 * This also works with mounts and links.
3832 * Don't do this for MS-DOS, it will change the "current dir" for a drive.
Bram Moolenaar25a494c2018-11-16 19:39:50 +01003833 * For Windows:
3834 * This code is duplicated in init_homedir() in dosinst.c. Keep in sync!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 */
3836static char_u *homedir = NULL;
3837
3838 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003839init_homedir(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840{
3841 char_u *var;
3842
Bram Moolenaar05159a02005-02-26 23:04:13 +00003843 /* In case we are called a second time (when 'encoding' changes). */
Bram Moolenaard23a8232018-02-10 18:45:26 +01003844 VIM_CLEAR(homedir);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003845
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846#ifdef VMS
3847 var = mch_getenv((char_u *)"SYS$LOGIN");
3848#else
3849 var = mch_getenv((char_u *)"HOME");
3850#endif
3851
Bram Moolenaar071d4272004-06-13 20:20:40 +00003852#ifdef WIN3264
3853 /*
Bram Moolenaar48340b62017-08-29 22:08:53 +02003854 * Typically, $HOME is not defined on Windows, unless the user has
3855 * specifically defined it for Vim's sake. However, on Windows NT
3856 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
3857 * each user. Try constructing $HOME from these.
3858 */
Bram Moolenaarb47a2592017-08-30 13:22:28 +02003859 if (var == NULL || *var == NUL)
Bram Moolenaar48340b62017-08-29 22:08:53 +02003860 {
3861 char_u *homedrive, *homepath;
3862
3863 homedrive = mch_getenv((char_u *)"HOMEDRIVE");
3864 homepath = mch_getenv((char_u *)"HOMEPATH");
3865 if (homepath == NULL || *homepath == NUL)
3866 homepath = (char_u *)"\\";
3867 if (homedrive != NULL
3868 && STRLEN(homedrive) + STRLEN(homepath) < MAXPATHL)
3869 {
3870 sprintf((char *)NameBuff, "%s%s", homedrive, homepath);
3871 if (NameBuff[0] != NUL)
3872 var = NameBuff;
3873 }
3874 }
3875
3876 if (var == NULL)
3877 var = mch_getenv((char_u *)"USERPROFILE");
3878
3879 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880 * Weird but true: $HOME may contain an indirect reference to another
3881 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
3882 * when $HOME is being set.
3883 */
3884 if (var != NULL && *var == '%')
3885 {
3886 char_u *p;
3887 char_u *exp;
3888
3889 p = vim_strchr(var + 1, '%');
3890 if (p != NULL)
3891 {
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003892 vim_strncpy(NameBuff, var + 1, p - (var + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 exp = mch_getenv(NameBuff);
3894 if (exp != NULL && *exp != NUL
3895 && STRLEN(exp) + STRLEN(p) < MAXPATHL)
3896 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003897 vim_snprintf((char *)NameBuff, MAXPATHL, "%s%s", exp, p + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 var = NameBuff;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899 }
3900 }
3901 }
3902
Bram Moolenaar48340b62017-08-29 22:08:53 +02003903 if (var != NULL && *var == NUL) /* empty is same as not set */
3904 var = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905
Bram Moolenaar05159a02005-02-26 23:04:13 +00003906 if (enc_utf8 && var != NULL)
3907 {
3908 int len;
Bram Moolenaarb453a532011-04-28 17:48:44 +02003909 char_u *pp = NULL;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003910
3911 /* Convert from active codepage to UTF-8. Other conversions are
3912 * not done, because they would fail for non-ASCII characters. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003913 acp_to_enc(var, (int)STRLEN(var), &pp, &len);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003914 if (pp != NULL)
3915 {
3916 homedir = pp;
3917 return;
3918 }
3919 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920
Bram Moolenaar071d4272004-06-13 20:20:40 +00003921 /*
3922 * Default home dir is C:/
3923 * Best assumption we can make in such a situation.
3924 */
3925 if (var == NULL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003926 var = (char_u *)"C:/";
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927#endif
Bram Moolenaar48340b62017-08-29 22:08:53 +02003928
Bram Moolenaar071d4272004-06-13 20:20:40 +00003929 if (var != NULL)
3930 {
3931#ifdef UNIX
3932 /*
3933 * Change to the directory and get the actual path. This resolves
3934 * links. Don't do it when we can't return.
3935 */
3936 if (mch_dirname(NameBuff, MAXPATHL) == OK
3937 && mch_chdir((char *)NameBuff) == 0)
3938 {
3939 if (!mch_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
3940 var = IObuff;
3941 if (mch_chdir((char *)NameBuff) != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003942 emsg(_(e_prev_dir));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943 }
3944#endif
3945 homedir = vim_strsave(var);
3946 }
3947}
3948
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003949#if defined(EXITFREE) || defined(PROTO)
3950 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003951free_homedir(void)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003952{
3953 vim_free(homedir);
3954}
Bram Moolenaar24305862012-08-15 14:05:05 +02003955
3956# ifdef FEAT_CMDL_COMPL
3957 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003958free_users(void)
Bram Moolenaar24305862012-08-15 14:05:05 +02003959{
3960 ga_clear_strings(&ga_users);
3961}
3962# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003963#endif
3964
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965/*
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00003966 * Call expand_env() and store the result in an allocated string.
3967 * This is not very memory efficient, this expects the result to be freed
3968 * again soon.
3969 */
3970 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01003971expand_env_save(char_u *src)
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00003972{
3973 return expand_env_save_opt(src, FALSE);
3974}
3975
3976/*
3977 * Idem, but when "one" is TRUE handle the string as one file name, only
3978 * expand "~" at the start.
3979 */
3980 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01003981expand_env_save_opt(char_u *src, int one)
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00003982{
3983 char_u *p;
3984
3985 p = alloc(MAXPATHL);
3986 if (p != NULL)
3987 expand_env_esc(src, p, MAXPATHL, FALSE, one, NULL);
3988 return p;
3989}
3990
3991/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992 * Expand environment variable with path name.
3993 * "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00003994 * Skips over "\ ", "\~" and "\$" (not for Win32 though).
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 * If anything fails no expansion is done and dst equals src.
3996 */
3997 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01003998expand_env(
3999 char_u *src, /* input string e.g. "$HOME/vim.hlp" */
4000 char_u *dst, /* where to put the result */
4001 int dstlen) /* maximum length of the result */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002{
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00004003 expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004}
4005
4006 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01004007expand_env_esc(
4008 char_u *srcp, /* input string e.g. "$HOME/vim.hlp" */
4009 char_u *dst, /* where to put the result */
4010 int dstlen, /* maximum length of the result */
4011 int esc, /* escape spaces in expanded variables */
4012 int one, /* "srcp" is one file name */
4013 char_u *startstr) /* start again after this (can be NULL) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014{
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00004015 char_u *src;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 char_u *tail;
4017 int c;
4018 char_u *var;
4019 int copy_char;
4020 int mustfree; /* var was allocated, need to free it later */
4021 int at_start = TRUE; /* at start of a name */
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00004022 int startstr_len = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00004024 if (startstr != NULL)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004025 startstr_len = (int)STRLEN(startstr);
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00004026
4027 src = skipwhite(srcp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 --dstlen; /* leave one char space for "\," */
4029 while (*src && dstlen > 0)
4030 {
Bram Moolenaarbe83b732015-08-25 14:21:19 +02004031#ifdef FEAT_EVAL
4032 /* Skip over `=expr`. */
4033 if (src[0] == '`' && src[1] == '=')
4034 {
4035 size_t len;
4036
4037 var = src;
4038 src += 2;
4039 (void)skip_expr(&src);
4040 if (*src == '`')
4041 ++src;
4042 len = src - var;
4043 if (len > (size_t)dstlen)
4044 len = dstlen;
4045 vim_strncpy(dst, var, len);
4046 dst += len;
Bram Moolenaar5df1ed22015-09-01 16:25:34 +02004047 dstlen -= (int)len;
Bram Moolenaarbe83b732015-08-25 14:21:19 +02004048 continue;
4049 }
4050#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051 copy_char = TRUE;
Bram Moolenaard4755bb2004-09-02 19:12:26 +00004052 if ((*src == '$'
4053#ifdef VMS
4054 && at_start
4055#endif
4056 )
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004057#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004058 || *src == '%'
4059#endif
4060 || (*src == '~' && at_start))
4061 {
4062 mustfree = FALSE;
4063
4064 /*
4065 * The variable name is copied into dst temporarily, because it may
4066 * be a string in read-only memory and a NUL needs to be appended.
4067 */
4068 if (*src != '~') /* environment var */
4069 {
4070 tail = src + 1;
4071 var = dst;
4072 c = dstlen - 1;
4073
4074#ifdef UNIX
4075 /* Unix has ${var-name} type environment vars */
4076 if (*tail == '{' && !vim_isIDc('{'))
4077 {
4078 tail++; /* ignore '{' */
4079 while (c-- > 0 && *tail && *tail != '}')
4080 *var++ = *tail++;
4081 }
4082 else
4083#endif
4084 {
4085 while (c-- > 0 && *tail != NUL && ((vim_isIDc(*tail))
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004086#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 || (*src == '%' && *tail != '%')
4088#endif
4089 ))
4090 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 *var++ = *tail++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 }
4093 }
4094
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004095#if defined(MSWIN) || defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096# ifdef UNIX
4097 if (src[1] == '{' && *tail != '}')
4098# else
4099 if (*src == '%' && *tail != '%')
4100# endif
4101 var = NULL;
4102 else
4103 {
4104# ifdef UNIX
4105 if (src[1] == '{')
4106# else
4107 if (*src == '%')
4108#endif
4109 ++tail;
4110#endif
4111 *var = NUL;
4112 var = vim_getenv(dst, &mustfree);
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004113#if defined(MSWIN) || defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 }
4115#endif
4116 }
4117 /* home directory */
4118 else if ( src[1] == NUL
4119 || vim_ispathsep(src[1])
4120 || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL)
4121 {
4122 var = homedir;
4123 tail = src + 1;
4124 }
4125 else /* user directory */
4126 {
4127#if defined(UNIX) || (defined(VMS) && defined(USER_HOME))
4128 /*
4129 * Copy ~user to dst[], so we can put a NUL after it.
4130 */
4131 tail = src;
4132 var = dst;
4133 c = dstlen - 1;
4134 while ( c-- > 0
4135 && *tail
4136 && vim_isfilec(*tail)
4137 && !vim_ispathsep(*tail))
4138 *var++ = *tail++;
4139 *var = NUL;
4140# ifdef UNIX
4141 /*
4142 * If the system supports getpwnam(), use it.
4143 * Otherwise, or if getpwnam() fails, the shell is used to
4144 * expand ~user. This is slower and may fail if the shell
4145 * does not support ~user (old versions of /bin/sh).
4146 */
4147# if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
4148 {
Bram Moolenaara40ceaf2006-01-13 22:35:40 +00004149 /* Note: memory allocated by getpwnam() is never freed.
4150 * Calling endpwent() apparently doesn't help. */
Bram Moolenaar187a4f22017-02-23 17:07:14 +01004151 struct passwd *pw = (*dst == NUL)
4152 ? NULL : getpwnam((char *)dst + 1);
4153
4154 var = (pw == NULL) ? NULL : (char_u *)pw->pw_dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004155 }
4156 if (var == NULL)
4157# endif
4158 {
4159 expand_T xpc;
4160
4161 ExpandInit(&xpc);
4162 xpc.xp_context = EXPAND_FILES;
4163 var = ExpandOne(&xpc, dst, NULL,
4164 WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165 mustfree = TRUE;
4166 }
4167
4168# else /* !UNIX, thus VMS */
4169 /*
4170 * USER_HOME is a comma-separated list of
4171 * directories to search for the user account in.
4172 */
4173 {
4174 char_u test[MAXPATHL], paths[MAXPATHL];
4175 char_u *path, *next_path, *ptr;
Bram Moolenaar8767f522016-07-01 17:17:39 +02004176 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177
4178 STRCPY(paths, USER_HOME);
4179 next_path = paths;
4180 while (*next_path)
4181 {
4182 for (path = next_path; *next_path && *next_path != ',';
4183 next_path++);
4184 if (*next_path)
4185 *next_path++ = NUL;
4186 STRCPY(test, path);
4187 STRCAT(test, "/");
4188 STRCAT(test, dst + 1);
4189 if (mch_stat(test, &st) == 0)
4190 {
4191 var = alloc(STRLEN(test) + 1);
4192 STRCPY(var, test);
4193 mustfree = TRUE;
4194 break;
4195 }
4196 }
4197 }
4198# endif /* UNIX */
4199#else
4200 /* cannot expand user's home directory, so don't try */
4201 var = NULL;
4202 tail = (char_u *)""; /* for gcc */
4203#endif /* UNIX || VMS */
4204 }
4205
4206#ifdef BACKSLASH_IN_FILENAME
4207 /* If 'shellslash' is set change backslashes to forward slashes.
4208 * Can't use slash_adjust(), p_ssl may be set temporarily. */
4209 if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL)
4210 {
4211 char_u *p = vim_strsave(var);
4212
4213 if (p != NULL)
4214 {
4215 if (mustfree)
4216 vim_free(var);
4217 var = p;
4218 mustfree = TRUE;
4219 forward_slash(var);
4220 }
4221 }
4222#endif
4223
4224 /* If "var" contains white space, escape it with a backslash.
4225 * Required for ":e ~/tt" when $HOME includes a space. */
4226 if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL)
4227 {
4228 char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
4229
4230 if (p != NULL)
4231 {
4232 if (mustfree)
4233 vim_free(var);
4234 var = p;
4235 mustfree = TRUE;
4236 }
4237 }
4238
4239 if (var != NULL && *var != NUL
4240 && (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
4241 {
4242 STRCPY(dst, var);
4243 dstlen -= (int)STRLEN(var);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004244 c = (int)STRLEN(var);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245 /* if var[] ends in a path separator and tail[] starts
4246 * with it, skip a character */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004247 if (*var != NUL && after_pathsep(dst, dst + c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248#if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA)
4249 && dst[-1] != ':'
4250#endif
4251 && vim_ispathsep(*tail))
4252 ++tail;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004253 dst += c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 src = tail;
4255 copy_char = FALSE;
4256 }
4257 if (mustfree)
4258 vim_free(var);
4259 }
4260
4261 if (copy_char) /* copy at least one char */
4262 {
4263 /*
Bram Moolenaar25394022007-05-10 19:06:20 +00004264 * Recognize the start of a new name, for '~'.
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00004265 * Don't do this when "one" is TRUE, to avoid expanding "~" in
4266 * ":edit foo ~ foo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 */
4268 at_start = FALSE;
4269 if (src[0] == '\\' && src[1] != NUL)
4270 {
4271 *dst++ = *src++;
4272 --dstlen;
4273 }
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00004274 else if ((src[0] == ' ' || src[0] == ',') && !one)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275 at_start = TRUE;
Bram Moolenaar1c864092017-08-06 18:15:45 +02004276 if (dstlen > 0)
4277 {
4278 *dst++ = *src++;
4279 --dstlen;
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00004280
Bram Moolenaar1c864092017-08-06 18:15:45 +02004281 if (startstr != NULL && src - startstr_len >= srcp
4282 && STRNCMP(src - startstr_len, startstr,
4283 startstr_len) == 0)
4284 at_start = TRUE;
4285 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286 }
Bram Moolenaar1c864092017-08-06 18:15:45 +02004287
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288 }
4289 *dst = NUL;
4290}
4291
4292/*
4293 * Vim's version of getenv().
4294 * Special handling of $HOME, $VIM and $VIMRUNTIME.
Bram Moolenaar2f6b0b82005-03-08 22:43:10 +00004295 * Also does ACP to 'enc' conversion for Win32.
Bram Moolenaarb453a532011-04-28 17:48:44 +02004296 * "mustfree" is set to TRUE when returned is allocated, it must be
4297 * initialized to FALSE by the caller.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298 */
4299 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01004300vim_getenv(char_u *name, int *mustfree)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301{
4302 char_u *p;
4303 char_u *pend;
4304 int vimruntime;
4305
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004306#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004307 /* use "C:/" when $HOME is not set */
4308 if (STRCMP(name, "HOME") == 0)
4309 return homedir;
4310#endif
4311
4312 p = mch_getenv(name);
4313 if (p != NULL && *p == NUL) /* empty is the same as not set */
4314 p = NULL;
4315
4316 if (p != NULL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004317 {
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01004318#if defined(WIN3264)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004319 if (enc_utf8)
4320 {
4321 int len;
Bram Moolenaarb453a532011-04-28 17:48:44 +02004322 char_u *pp = NULL;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004323
4324 /* Convert from active codepage to UTF-8. Other conversions are
4325 * not done, because they would fail for non-ASCII characters. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004326 acp_to_enc(p, (int)STRLEN(p), &pp, &len);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004327 if (pp != NULL)
4328 {
4329 p = pp;
4330 *mustfree = TRUE;
4331 }
4332 }
4333#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334 return p;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004335 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004336
4337 vimruntime = (STRCMP(name, "VIMRUNTIME") == 0);
4338 if (!vimruntime && STRCMP(name, "VIM") != 0)
4339 return NULL;
4340
4341 /*
4342 * When expanding $VIMRUNTIME fails, try using $VIM/vim<version> or $VIM.
4343 * Don't do this when default_vimruntime_dir is non-empty.
4344 */
4345 if (vimruntime
4346#ifdef HAVE_PATHDEF
4347 && *default_vimruntime_dir == NUL
4348#endif
4349 )
4350 {
4351 p = mch_getenv((char_u *)"VIM");
4352 if (p != NULL && *p == NUL) /* empty is the same as not set */
4353 p = NULL;
4354 if (p != NULL)
4355 {
4356 p = vim_version_dir(p);
4357 if (p != NULL)
4358 *mustfree = TRUE;
4359 else
4360 p = mch_getenv((char_u *)"VIM");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004361
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01004362#if defined(WIN3264)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004363 if (enc_utf8)
4364 {
4365 int len;
Bram Moolenaarb453a532011-04-28 17:48:44 +02004366 char_u *pp = NULL;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004367
4368 /* Convert from active codepage to UTF-8. Other conversions
4369 * are not done, because they would fail for non-ASCII
4370 * characters. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004371 acp_to_enc(p, (int)STRLEN(p), &pp, &len);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004372 if (pp != NULL)
4373 {
Bram Moolenaarb453a532011-04-28 17:48:44 +02004374 if (*mustfree)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004375 vim_free(p);
4376 p = pp;
4377 *mustfree = TRUE;
4378 }
4379 }
4380#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381 }
4382 }
4383
4384 /*
4385 * When expanding $VIM or $VIMRUNTIME fails, try using:
4386 * - the directory name from 'helpfile' (unless it contains '$')
4387 * - the executable name from argv[0]
4388 */
4389 if (p == NULL)
4390 {
4391 if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL)
4392 p = p_hf;
4393#ifdef USE_EXE_NAME
4394 /*
4395 * Use the name of the executable, obtained from argv[0].
4396 */
4397 else
4398 p = exe_name;
4399#endif
4400 if (p != NULL)
4401 {
4402 /* remove the file name */
4403 pend = gettail(p);
4404
4405 /* remove "doc/" from 'helpfile', if present */
4406 if (p == p_hf)
4407 pend = remove_tail(p, pend, (char_u *)"doc");
4408
4409#ifdef USE_EXE_NAME
4410# ifdef MACOS_X
Bram Moolenaar95e9b492006-03-15 23:04:43 +00004411 /* remove "MacOS" from exe_name and add "Resources/vim" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412 if (p == exe_name)
4413 {
4414 char_u *pend1;
Bram Moolenaar95e9b492006-03-15 23:04:43 +00004415 char_u *pnew;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416
Bram Moolenaar95e9b492006-03-15 23:04:43 +00004417 pend1 = remove_tail(p, pend, (char_u *)"MacOS");
4418 if (pend1 != pend)
4419 {
4420 pnew = alloc((unsigned)(pend1 - p) + 15);
4421 if (pnew != NULL)
4422 {
4423 STRNCPY(pnew, p, (pend1 - p));
4424 STRCPY(pnew + (pend1 - p), "Resources/vim");
4425 p = pnew;
4426 pend = p + STRLEN(p);
4427 }
4428 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 }
4430# endif
4431 /* remove "src/" from exe_name, if present */
4432 if (p == exe_name)
4433 pend = remove_tail(p, pend, (char_u *)"src");
4434#endif
4435
4436 /* for $VIM, remove "runtime/" or "vim54/", if present */
4437 if (!vimruntime)
4438 {
4439 pend = remove_tail(p, pend, (char_u *)RUNTIME_DIRNAME);
4440 pend = remove_tail(p, pend, (char_u *)VIM_VERSION_NODOT);
4441 }
4442
4443 /* remove trailing path separator */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004444 if (pend > p && after_pathsep(p, pend))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445 --pend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446
Bram Moolenaar95e9b492006-03-15 23:04:43 +00004447#ifdef MACOS_X
4448 if (p == exe_name || p == p_hf)
4449#endif
4450 /* check that the result is a directory name */
4451 p = vim_strnsave(p, (int)(pend - p));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452
4453 if (p != NULL && !mch_isdir(p))
Bram Moolenaard23a8232018-02-10 18:45:26 +01004454 VIM_CLEAR(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 else
4456 {
4457#ifdef USE_EXE_NAME
4458 /* may add "/vim54" or "/runtime" if it exists */
4459 if (vimruntime && (pend = vim_version_dir(p)) != NULL)
4460 {
4461 vim_free(p);
4462 p = pend;
4463 }
4464#endif
4465 *mustfree = TRUE;
4466 }
4467 }
4468 }
4469
4470#ifdef HAVE_PATHDEF
4471 /* When there is a pathdef.c file we can use default_vim_dir and
4472 * default_vimruntime_dir */
4473 if (p == NULL)
4474 {
4475 /* Only use default_vimruntime_dir when it is not empty */
4476 if (vimruntime && *default_vimruntime_dir != NUL)
4477 {
4478 p = default_vimruntime_dir;
4479 *mustfree = FALSE;
4480 }
4481 else if (*default_vim_dir != NUL)
4482 {
4483 if (vimruntime && (p = vim_version_dir(default_vim_dir)) != NULL)
4484 *mustfree = TRUE;
4485 else
4486 {
4487 p = default_vim_dir;
4488 *mustfree = FALSE;
4489 }
4490 }
4491 }
4492#endif
4493
4494 /*
4495 * Set the environment variable, so that the new value can be found fast
4496 * next time, and others can also use it (e.g. Perl).
4497 */
4498 if (p != NULL)
4499 {
4500 if (vimruntime)
4501 {
4502 vim_setenv((char_u *)"VIMRUNTIME", p);
4503 didset_vimruntime = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004504 }
4505 else
4506 {
4507 vim_setenv((char_u *)"VIM", p);
4508 didset_vim = TRUE;
4509 }
4510 }
4511 return p;
4512}
4513
4514/*
4515 * Check if the directory "vimdir/<version>" or "vimdir/runtime" exists.
4516 * Return NULL if not, return its name in allocated memory otherwise.
4517 */
4518 static char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01004519vim_version_dir(char_u *vimdir)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520{
4521 char_u *p;
4522
4523 if (vimdir == NULL || *vimdir == NUL)
4524 return NULL;
4525 p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, TRUE);
4526 if (p != NULL && mch_isdir(p))
4527 return p;
4528 vim_free(p);
4529 p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, TRUE);
4530 if (p != NULL && mch_isdir(p))
4531 return p;
4532 vim_free(p);
4533 return NULL;
4534}
4535
4536/*
4537 * If the string between "p" and "pend" ends in "name/", return "pend" minus
4538 * the length of "name/". Otherwise return "pend".
4539 */
4540 static char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01004541remove_tail(char_u *p, char_u *pend, char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542{
4543 int len = (int)STRLEN(name) + 1;
4544 char_u *newend = pend - len;
4545
4546 if (newend >= p
4547 && fnamencmp(newend, name, len - 1) == 0
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004548 && (newend == p || after_pathsep(p, newend)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 return newend;
4550 return pend;
4551}
4552
Bram Moolenaar113e1072019-01-20 15:30:40 +01004553#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar137374f2018-05-13 15:59:50 +02004554 void
4555vim_unsetenv(char_u *var)
4556{
4557#ifdef HAVE_UNSETENV
4558 unsetenv((char *)var);
4559#else
Bram Moolenaar1af6a4b2018-05-14 22:58:34 +02004560 vim_setenv(var, (char_u *)"");
Bram Moolenaar137374f2018-05-13 15:59:50 +02004561#endif
4562}
Bram Moolenaar113e1072019-01-20 15:30:40 +01004563#endif
Bram Moolenaar137374f2018-05-13 15:59:50 +02004564
4565
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004567 * Our portable version of setenv.
4568 */
4569 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01004570vim_setenv(char_u *name, char_u *val)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571{
4572#ifdef HAVE_SETENV
4573 mch_setenv((char *)name, (char *)val, 1);
4574#else
4575 char_u *envbuf;
4576
4577 /*
4578 * Putenv does not copy the string, it has to remain
4579 * valid. The allocated memory will never be freed.
4580 */
4581 envbuf = alloc((unsigned)(STRLEN(name) + STRLEN(val) + 2));
4582 if (envbuf != NULL)
4583 {
4584 sprintf((char *)envbuf, "%s=%s", name, val);
4585 putenv((char *)envbuf);
4586 }
4587#endif
Bram Moolenaar011a34d2012-02-29 13:49:09 +01004588#ifdef FEAT_GETTEXT
4589 /*
4590 * When setting $VIMRUNTIME adjust the directory to find message
4591 * translations to $VIMRUNTIME/lang.
4592 */
4593 if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0)
4594 {
4595 char_u *buf = concat_str(val, (char_u *)"/lang");
4596
4597 if (buf != NULL)
4598 {
4599 bindtextdomain(VIMPACKAGE, (char *)buf);
4600 vim_free(buf);
4601 }
4602 }
4603#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604}
4605
4606#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4607/*
4608 * Function given to ExpandGeneric() to obtain an environment variable name.
4609 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01004611get_env_name(
4612 expand_T *xp UNUSED,
4613 int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614{
Bram Moolenaard0573012017-10-28 21:11:06 +02004615# if defined(AMIGA)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 /*
Bram Moolenaard0573012017-10-28 21:11:06 +02004617 * No environ[] on the Amiga.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618 */
4619 return NULL;
4620# else
4621# ifndef __WIN32__
4622 /* Borland C++ 5.2 has this in a header file. */
4623 extern char **environ;
4624# endif
Bram Moolenaar21cf8232004-07-16 20:18:37 +00004625# define ENVNAMELEN 100
4626 static char_u name[ENVNAMELEN];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 char_u *str;
4628 int n;
4629
4630 str = (char_u *)environ[idx];
4631 if (str == NULL)
4632 return NULL;
4633
Bram Moolenaar21cf8232004-07-16 20:18:37 +00004634 for (n = 0; n < ENVNAMELEN - 1; ++n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004635 {
4636 if (str[n] == '=' || str[n] == NUL)
4637 break;
4638 name[n] = str[n];
4639 }
4640 name[n] = NUL;
4641 return name;
4642# endif
4643}
Bram Moolenaar24305862012-08-15 14:05:05 +02004644
4645/*
Bram Moolenaar6b0b83f2018-09-10 19:03:05 +02004646 * Add a user name to the list of users in ga_users.
4647 * Do nothing if user name is NULL or empty.
4648 */
4649 static void
4650add_user(char_u *user, int need_copy)
4651{
4652 char_u *user_copy = (user != NULL && need_copy)
4653 ? vim_strsave(user) : user;
4654
4655 if (user_copy == NULL || *user_copy == NUL || ga_grow(&ga_users, 1) == FAIL)
4656 {
4657 if (need_copy)
4658 vim_free(user);
4659 return;
4660 }
4661 ((char_u **)(ga_users.ga_data))[ga_users.ga_len++] = user_copy;
4662}
4663
4664/*
Bram Moolenaar24305862012-08-15 14:05:05 +02004665 * Find all user names for user completion.
4666 * Done only once and then cached.
4667 */
4668 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01004669init_users(void)
Bram Moolenaar01b626c2013-06-16 22:49:14 +02004670{
Bram Moolenaar24305862012-08-15 14:05:05 +02004671 static int lazy_init_done = FALSE;
4672
4673 if (lazy_init_done)
4674 return;
4675
4676 lazy_init_done = TRUE;
4677 ga_init2(&ga_users, sizeof(char_u *), 20);
4678
4679# if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
4680 {
Bram Moolenaar24305862012-08-15 14:05:05 +02004681 struct passwd* pw;
4682
4683 setpwent();
4684 while ((pw = getpwent()) != NULL)
Bram Moolenaar6b0b83f2018-09-10 19:03:05 +02004685 add_user((char_u *)pw->pw_name, TRUE);
Bram Moolenaar24305862012-08-15 14:05:05 +02004686 endpwent();
4687 }
Bram Moolenaar828c3d72018-06-19 18:58:07 +02004688# elif defined(WIN3264)
4689 {
Bram Moolenaar828c3d72018-06-19 18:58:07 +02004690 DWORD nusers = 0, ntotal = 0, i;
4691 PUSER_INFO_0 uinfo;
4692
4693 if (NetUserEnum(NULL, 0, 0, (LPBYTE *) &uinfo, MAX_PREFERRED_LENGTH,
4694 &nusers, &ntotal, NULL) == NERR_Success)
4695 {
4696 for (i = 0; i < nusers; i++)
Bram Moolenaar6b0b83f2018-09-10 19:03:05 +02004697 add_user(utf16_to_enc(uinfo[i].usri0_name, NULL), FALSE);
Bram Moolenaar828c3d72018-06-19 18:58:07 +02004698
4699 NetApiBufferFree(uinfo);
4700 }
4701 }
Bram Moolenaar24305862012-08-15 14:05:05 +02004702# endif
Bram Moolenaar6b0b83f2018-09-10 19:03:05 +02004703# if defined(HAVE_GETPWNAM)
4704 {
4705 char_u *user_env = mch_getenv((char_u *)"USER");
4706
4707 // The $USER environment variable may be a valid remote user name (NIS,
4708 // LDAP) not already listed by getpwent(), as getpwent() only lists
4709 // local user names. If $USER is not already listed, check whether it
4710 // is a valid remote user name using getpwnam() and if it is, add it to
4711 // the list of user names.
4712
4713 if (user_env != NULL && *user_env != NUL)
4714 {
4715 int i;
4716
4717 for (i = 0; i < ga_users.ga_len; i++)
4718 {
4719 char_u *local_user = ((char_u **)ga_users.ga_data)[i];
4720
4721 if (STRCMP(local_user, user_env) == 0)
4722 break;
4723 }
4724
4725 if (i == ga_users.ga_len)
4726 {
4727 struct passwd *pw = getpwnam((char *)user_env);
4728
4729 if (pw != NULL)
4730 add_user((char_u *)pw->pw_name, TRUE);
4731 }
4732 }
4733 }
4734# endif
Bram Moolenaar24305862012-08-15 14:05:05 +02004735}
4736
4737/*
4738 * Function given to ExpandGeneric() to obtain an user names.
4739 */
4740 char_u*
Bram Moolenaar9b578142016-01-30 19:39:49 +01004741get_users(expand_T *xp UNUSED, int idx)
Bram Moolenaar24305862012-08-15 14:05:05 +02004742{
4743 init_users();
4744 if (idx < ga_users.ga_len)
4745 return ((char_u **)ga_users.ga_data)[idx];
4746 return NULL;
4747}
4748
4749/*
4750 * Check whether name matches a user name. Return:
4751 * 0 if name does not match any user name.
4752 * 1 if name partially matches the beginning of a user name.
4753 * 2 is name fully matches a user name.
4754 */
Bram Moolenaar6c5d1042018-07-07 16:41:13 +02004755 int
4756match_user(char_u *name)
Bram Moolenaar24305862012-08-15 14:05:05 +02004757{
4758 int i;
4759 int n = (int)STRLEN(name);
4760 int result = 0;
4761
4762 init_users();
4763 for (i = 0; i < ga_users.ga_len; i++)
4764 {
4765 if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0)
4766 return 2; /* full match */
4767 if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0)
4768 result = 1; /* partial match */
4769 }
4770 return result;
4771}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772#endif
4773
4774/*
4775 * Replace home directory by "~" in each space or comma separated file name in
4776 * 'src'.
4777 * If anything fails (except when out of space) dst equals src.
4778 */
4779 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01004780home_replace(
4781 buf_T *buf, /* when not NULL, check for help files */
4782 char_u *src, /* input file name */
4783 char_u *dst, /* where to put the result */
4784 int dstlen, /* maximum length of the result */
4785 int one) /* if TRUE, only replace one file name, include
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 spaces and commas in the file name. */
4787{
4788 size_t dirlen = 0, envlen = 0;
4789 size_t len;
Bram Moolenaar9158f9e2012-06-20 14:02:27 +02004790 char_u *homedir_env, *homedir_env_orig;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 char_u *p;
4792
4793 if (src == NULL)
4794 {
4795 *dst = NUL;
4796 return;
4797 }
4798
4799 /*
4800 * If the file is a help file, remove the path completely.
4801 */
4802 if (buf != NULL && buf->b_help)
4803 {
Bram Moolenaar0af2d322017-08-05 23:00:53 +02004804 vim_snprintf((char *)dst, dstlen, "%s", gettail(src));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805 return;
4806 }
4807
4808 /*
4809 * We check both the value of the $HOME environment variable and the
4810 * "real" home directory.
4811 */
4812 if (homedir != NULL)
4813 dirlen = STRLEN(homedir);
4814
4815#ifdef VMS
Bram Moolenaar9158f9e2012-06-20 14:02:27 +02004816 homedir_env_orig = homedir_env = mch_getenv((char_u *)"SYS$LOGIN");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004817#else
Bram Moolenaar9158f9e2012-06-20 14:02:27 +02004818 homedir_env_orig = homedir_env = mch_getenv((char_u *)"HOME");
4819#endif
Bram Moolenaar48340b62017-08-29 22:08:53 +02004820#ifdef WIN3264
4821 if (homedir_env == NULL)
4822 homedir_env_orig = homedir_env = mch_getenv((char_u *)"USERPROFILE");
4823#endif
Bram Moolenaarbef47902012-07-06 16:49:40 +02004824 /* Empty is the same as not set. */
4825 if (homedir_env != NULL && *homedir_env == NUL)
4826 homedir_env = NULL;
4827
Bram Moolenaare60c2e52013-06-05 19:35:38 +02004828#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL)
Bram Moolenaaref0a1d52018-12-30 11:38:57 +01004829 if (homedir_env != NULL && *homedir_env == '~')
Bram Moolenaar9158f9e2012-06-20 14:02:27 +02004830 {
4831 int usedlen = 0;
4832 int flen;
4833 char_u *fbuf = NULL;
4834
4835 flen = (int)STRLEN(homedir_env);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02004836 (void)modify_fname((char_u *)":p", FALSE, &usedlen,
Bram Moolenaard12f8112012-06-20 17:56:09 +02004837 &homedir_env, &fbuf, &flen);
Bram Moolenaar9158f9e2012-06-20 14:02:27 +02004838 flen = (int)STRLEN(homedir_env);
4839 if (flen > 0 && vim_ispathsep(homedir_env[flen - 1]))
4840 /* Remove the trailing / that is added to a directory. */
4841 homedir_env[flen - 1] = NUL;
4842 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843#endif
4844
Bram Moolenaar071d4272004-06-13 20:20:40 +00004845 if (homedir_env != NULL)
4846 envlen = STRLEN(homedir_env);
4847
4848 if (!one)
4849 src = skipwhite(src);
4850 while (*src && dstlen > 0)
4851 {
4852 /*
4853 * Here we are at the beginning of a file name.
4854 * First, check to see if the beginning of the file name matches
4855 * $HOME or the "real" home directory. Check that there is a '/'
4856 * after the match (so that if e.g. the file is "/home/pieter/bla",
4857 * and the home directory is "/home/piet", the file does not end up
4858 * as "~er/bla" (which would seem to indicate the file "bla" in user
4859 * er's home directory)).
4860 */
4861 p = homedir;
4862 len = dirlen;
4863 for (;;)
4864 {
4865 if ( len
4866 && fnamencmp(src, p, len) == 0
4867 && (vim_ispathsep(src[len])
4868 || (!one && (src[len] == ',' || src[len] == ' '))
4869 || src[len] == NUL))
4870 {
4871 src += len;
4872 if (--dstlen > 0)
4873 *dst++ = '~';
4874
4875 /*
4876 * If it's just the home directory, add "/".
4877 */
4878 if (!vim_ispathsep(src[0]) && --dstlen > 0)
4879 *dst++ = '/';
4880 break;
4881 }
4882 if (p == homedir_env)
4883 break;
4884 p = homedir_env;
4885 len = envlen;
4886 }
4887
4888 /* if (!one) skip to separator: space or comma */
4889 while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0)
4890 *dst++ = *src++;
4891 /* skip separator */
4892 while ((*src == ' ' || *src == ',') && --dstlen > 0)
4893 *dst++ = *src++;
4894 }
4895 /* if (dstlen == 0) out of space, what to do??? */
4896
4897 *dst = NUL;
Bram Moolenaar9158f9e2012-06-20 14:02:27 +02004898
4899 if (homedir_env != homedir_env_orig)
4900 vim_free(homedir_env);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901}
4902
4903/*
4904 * Like home_replace, store the replaced string in allocated memory.
4905 * When something fails, NULL is returned.
4906 */
4907 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01004908home_replace_save(
4909 buf_T *buf, /* when not NULL, check for help files */
4910 char_u *src) /* input file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004911{
4912 char_u *dst;
4913 unsigned len;
4914
4915 len = 3; /* space for "~/" and trailing NUL */
4916 if (src != NULL) /* just in case */
4917 len += (unsigned)STRLEN(src);
4918 dst = alloc(len);
4919 if (dst != NULL)
4920 home_replace(buf, src, dst, len, TRUE);
4921 return dst;
4922}
4923
4924/*
4925 * Compare two file names and return:
4926 * FPC_SAME if they both exist and are the same file.
4927 * FPC_SAMEX if they both don't exist and have the same file name.
4928 * FPC_DIFF if they both exist and are different files.
4929 * FPC_NOTX if they both don't exist.
4930 * FPC_DIFFX if one of them doesn't exist.
4931 * For the first name environment variables are expanded
4932 */
4933 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01004934fullpathcmp(
4935 char_u *s1,
4936 char_u *s2,
4937 int checkname) /* when both don't exist, check file names */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004938{
4939#ifdef UNIX
4940 char_u exp1[MAXPATHL];
4941 char_u full1[MAXPATHL];
4942 char_u full2[MAXPATHL];
Bram Moolenaar8767f522016-07-01 17:17:39 +02004943 stat_T st1, st2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004944 int r1, r2;
4945
4946 expand_env(s1, exp1, MAXPATHL);
4947 r1 = mch_stat((char *)exp1, &st1);
4948 r2 = mch_stat((char *)s2, &st2);
4949 if (r1 != 0 && r2 != 0)
4950 {
4951 /* if mch_stat() doesn't work, may compare the names */
4952 if (checkname)
4953 {
4954 if (fnamecmp(exp1, s2) == 0)
4955 return FPC_SAMEX;
4956 r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE);
4957 r2 = vim_FullName(s2, full2, MAXPATHL, FALSE);
4958 if (r1 == OK && r2 == OK && fnamecmp(full1, full2) == 0)
4959 return FPC_SAMEX;
4960 }
4961 return FPC_NOTX;
4962 }
4963 if (r1 != 0 || r2 != 0)
4964 return FPC_DIFFX;
4965 if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
4966 return FPC_SAME;
4967 return FPC_DIFF;
4968#else
4969 char_u *exp1; /* expanded s1 */
4970 char_u *full1; /* full path of s1 */
4971 char_u *full2; /* full path of s2 */
4972 int retval = FPC_DIFF;
4973 int r1, r2;
4974
4975 /* allocate one buffer to store three paths (alloc()/free() is slow!) */
4976 if ((exp1 = alloc(MAXPATHL * 3)) != NULL)
4977 {
4978 full1 = exp1 + MAXPATHL;
4979 full2 = full1 + MAXPATHL;
4980
4981 expand_env(s1, exp1, MAXPATHL);
4982 r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE);
4983 r2 = vim_FullName(s2, full2, MAXPATHL, FALSE);
4984
4985 /* If vim_FullName() fails, the file probably doesn't exist. */
4986 if (r1 != OK && r2 != OK)
4987 {
4988 if (checkname && fnamecmp(exp1, s2) == 0)
4989 retval = FPC_SAMEX;
4990 else
4991 retval = FPC_NOTX;
4992 }
4993 else if (r1 != OK || r2 != OK)
4994 retval = FPC_DIFFX;
4995 else if (fnamecmp(full1, full2))
4996 retval = FPC_DIFF;
4997 else
4998 retval = FPC_SAME;
4999 vim_free(exp1);
5000 }
5001 return retval;
5002#endif
5003}
5004
5005/*
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005006 * Get the tail of a path: the file name.
Bram Moolenaar31710262010-08-13 13:36:15 +02005007 * When the path ends in a path separator the tail is the NUL after it.
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005008 * Fail safe: never returns NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005009 */
5010 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005011gettail(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012{
5013 char_u *p1, *p2;
5014
5015 if (fname == NULL)
5016 return (char_u *)"";
Bram Moolenaar69c35002013-11-04 02:54:12 +01005017 for (p1 = p2 = get_past_head(fname); *p2; ) /* find last part of path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018 {
Bram Moolenaar69c35002013-11-04 02:54:12 +01005019 if (vim_ispathsep_nocolon(*p2))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005020 p1 = p2 + 1;
Bram Moolenaar91acfff2017-03-12 19:22:36 +01005021 MB_PTR_ADV(p2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005022 }
5023 return p1;
5024}
5025
Bram Moolenaar31710262010-08-13 13:36:15 +02005026#if defined(FEAT_SEARCHPATH)
Bram Moolenaar31710262010-08-13 13:36:15 +02005027/*
5028 * Return the end of the directory name, on the first path
5029 * separator:
5030 * "/path/file", "/path/dir/", "/path//dir", "/file"
5031 * ^ ^ ^ ^
5032 */
5033 static char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005034gettail_dir(char_u *fname)
Bram Moolenaar31710262010-08-13 13:36:15 +02005035{
5036 char_u *dir_end = fname;
5037 char_u *next_dir_end = fname;
5038 int look_for_sep = TRUE;
5039 char_u *p;
5040
5041 for (p = fname; *p != NUL; )
5042 {
5043 if (vim_ispathsep(*p))
5044 {
5045 if (look_for_sep)
5046 {
5047 next_dir_end = p;
5048 look_for_sep = FALSE;
5049 }
5050 }
5051 else
5052 {
5053 if (!look_for_sep)
5054 dir_end = next_dir_end;
5055 look_for_sep = TRUE;
5056 }
Bram Moolenaar91acfff2017-03-12 19:22:36 +01005057 MB_PTR_ADV(p);
Bram Moolenaar31710262010-08-13 13:36:15 +02005058 }
5059 return dir_end;
5060}
5061#endif
5062
Bram Moolenaar071d4272004-06-13 20:20:40 +00005063/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005064 * Get pointer to tail of "fname", including path separators. Putting a NUL
5065 * here leaves the directory name. Takes care of "c:/" and "//".
5066 * Always returns a valid pointer.
5067 */
5068 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005069gettail_sep(char_u *fname)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005070{
5071 char_u *p;
5072 char_u *t;
5073
5074 p = get_past_head(fname); /* don't remove the '/' from "c:/file" */
5075 t = gettail(fname);
5076 while (t > p && after_pathsep(fname, t))
5077 --t;
5078#ifdef VMS
5079 /* path separator is part of the path */
5080 ++t;
5081#endif
5082 return t;
5083}
5084
5085/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 * get the next path component (just after the next path separator).
5087 */
5088 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005089getnextcomp(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090{
5091 while (*fname && !vim_ispathsep(*fname))
Bram Moolenaar91acfff2017-03-12 19:22:36 +01005092 MB_PTR_ADV(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093 if (*fname)
5094 ++fname;
5095 return fname;
5096}
5097
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098/*
5099 * Get a pointer to one character past the head of a path name.
5100 * Unix: after "/"; DOS: after "c:\"; Amiga: after "disk:/"; Mac: no head.
5101 * If there is no head, path is returned.
5102 */
5103 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005104get_past_head(char_u *path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005105{
5106 char_u *retval;
5107
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005108#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109 /* may skip "c:" */
5110 if (isalpha(path[0]) && path[1] == ':')
5111 retval = path + 2;
5112 else
5113 retval = path;
5114#else
5115# if defined(AMIGA)
5116 /* may skip "label:" */
5117 retval = vim_strchr(path, ':');
5118 if (retval == NULL)
5119 retval = path;
5120# else /* Unix */
5121 retval = path;
5122# endif
5123#endif
5124
5125 while (vim_ispathsep(*retval))
5126 ++retval;
5127
5128 return retval;
5129}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005130
5131/*
Bram Moolenaar69c35002013-11-04 02:54:12 +01005132 * Return TRUE if 'c' is a path separator.
5133 * Note that for MS-Windows this includes the colon.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134 */
5135 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005136vim_ispathsep(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005137{
Bram Moolenaare60acc12011-05-10 16:41:25 +02005138#ifdef UNIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139 return (c == '/'); /* UNIX has ':' inside file names */
Bram Moolenaare60acc12011-05-10 16:41:25 +02005140#else
5141# ifdef BACKSLASH_IN_FILENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142 return (c == ':' || c == '/' || c == '\\');
Bram Moolenaare60acc12011-05-10 16:41:25 +02005143# else
5144# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145 /* server"user passwd"::device:[full.path.name]fname.extension;version" */
5146 return (c == ':' || c == '[' || c == ']' || c == '/'
5147 || c == '<' || c == '>' || c == '"' );
Bram Moolenaare60acc12011-05-10 16:41:25 +02005148# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 return (c == ':' || c == '/');
Bram Moolenaare60acc12011-05-10 16:41:25 +02005150# endif /* VMS */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005151# endif
Bram Moolenaare60acc12011-05-10 16:41:25 +02005152#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005153}
5154
Bram Moolenaar69c35002013-11-04 02:54:12 +01005155/*
5156 * Like vim_ispathsep(c), but exclude the colon for MS-Windows.
5157 */
5158 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005159vim_ispathsep_nocolon(int c)
Bram Moolenaar69c35002013-11-04 02:54:12 +01005160{
5161 return vim_ispathsep(c)
5162#ifdef BACKSLASH_IN_FILENAME
5163 && c != ':'
5164#endif
5165 ;
5166}
5167
Bram Moolenaar071d4272004-06-13 20:20:40 +00005168#if defined(FEAT_SEARCHPATH) || defined(PROTO)
5169/*
5170 * return TRUE if 'c' is a path list separator.
5171 */
5172 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005173vim_ispathlistsep(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174{
5175#ifdef UNIX
5176 return (c == ':');
5177#else
Bram Moolenaar25394022007-05-10 19:06:20 +00005178 return (c == ';'); /* might not be right for every system... */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179#endif
5180}
5181#endif
5182
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005183/*
5184 * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname"
5185 * It's done in-place.
5186 */
5187 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005188shorten_dir(char_u *str)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005189{
5190 char_u *tail, *s, *d;
5191 int skip = FALSE;
5192
5193 tail = gettail(str);
5194 d = str;
5195 for (s = str; ; ++s)
5196 {
5197 if (s >= tail) /* copy the whole tail */
5198 {
5199 *d++ = *s;
5200 if (*s == NUL)
5201 break;
5202 }
5203 else if (vim_ispathsep(*s)) /* copy '/' and next char */
5204 {
5205 *d++ = *s;
5206 skip = FALSE;
5207 }
5208 else if (!skip)
5209 {
5210 *d++ = *s; /* copy next char */
5211 if (*s != '~' && *s != '.') /* and leading "~" and "." */
5212 skip = TRUE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005213 if (has_mbyte)
5214 {
5215 int l = mb_ptr2len(s);
5216
5217 while (--l > 0)
Bram Moolenaarb6baca52006-08-15 20:24:14 +00005218 *d++ = *++s;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005219 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005220 }
5221 }
5222}
Bram Moolenaar910f66f2006-04-05 20:41:53 +00005223
Bram Moolenaar900b4d72005-12-12 22:05:50 +00005224/*
5225 * Return TRUE if the directory of "fname" exists, FALSE otherwise.
5226 * Also returns TRUE if there is no directory name.
5227 * "fname" must be writable!.
5228 */
5229 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005230dir_of_file_exists(char_u *fname)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00005231{
5232 char_u *p;
5233 int c;
5234 int retval;
5235
5236 p = gettail_sep(fname);
5237 if (p == fname)
5238 return TRUE;
5239 c = *p;
5240 *p = NUL;
5241 retval = mch_isdir(fname);
5242 *p = c;
5243 return retval;
5244}
5245
Bram Moolenaar071d4272004-06-13 20:20:40 +00005246/*
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01005247 * Versions of fnamecmp() and fnamencmp() that handle '/' and '\' equally
5248 * and deal with 'fileignorecase'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005249 */
5250 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005251vim_fnamecmp(char_u *x, char_u *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252{
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01005253#ifdef BACKSLASH_IN_FILENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00005254 return vim_fnamencmp(x, y, MAXPATHL);
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01005255#else
5256 if (p_fic)
5257 return MB_STRICMP(x, y);
5258 return STRCMP(x, y);
5259#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260}
5261
5262 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005263vim_fnamencmp(char_u *x, char_u *y, size_t len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005264{
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01005265#ifdef BACKSLASH_IN_FILENAME
Bram Moolenaard0e2d942013-03-19 18:31:49 +01005266 char_u *px = x;
5267 char_u *py = y;
5268 int cx = NUL;
5269 int cy = NUL;
5270
Bram Moolenaard0e2d942013-03-19 18:31:49 +01005271 while (len > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272 {
Bram Moolenaard0e2d942013-03-19 18:31:49 +01005273 cx = PTR2CHAR(px);
5274 cy = PTR2CHAR(py);
5275 if (cx == NUL || cy == NUL
5276 || ((p_fic ? MB_TOLOWER(cx) != MB_TOLOWER(cy) : cx != cy)
5277 && !(cx == '/' && cy == '\\')
5278 && !(cx == '\\' && cy == '/')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005279 break;
Bram Moolenaard0e2d942013-03-19 18:31:49 +01005280 len -= MB_PTR2LEN(px);
5281 px += MB_PTR2LEN(px);
5282 py += MB_PTR2LEN(py);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283 }
5284 if (len == 0)
5285 return 0;
Bram Moolenaard0e2d942013-03-19 18:31:49 +01005286 return (cx - cy);
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01005287#else
5288 if (p_fic)
5289 return MB_STRNICMP(x, y, len);
5290 return STRNCMP(x, y, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291#endif
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01005292}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005293
5294/*
5295 * Concatenate file names fname1 and fname2 into allocated memory.
Bram Moolenaar25394022007-05-10 19:06:20 +00005296 * Only add a '/' or '\\' when 'sep' is TRUE and it is necessary.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005297 */
5298 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005299concat_fnames(char_u *fname1, char_u *fname2, int sep)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005300{
5301 char_u *dest;
5302
5303 dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 3));
5304 if (dest != NULL)
5305 {
5306 STRCPY(dest, fname1);
5307 if (sep)
5308 add_pathsep(dest);
5309 STRCAT(dest, fname2);
5310 }
5311 return dest;
5312}
5313
Bram Moolenaard6754642005-01-17 22:18:45 +00005314/*
5315 * Concatenate two strings and return the result in allocated memory.
5316 * Returns NULL when out of memory.
5317 */
5318 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005319concat_str(char_u *str1, char_u *str2)
Bram Moolenaard6754642005-01-17 22:18:45 +00005320{
5321 char_u *dest;
5322 size_t l = STRLEN(str1);
5323
5324 dest = alloc((unsigned)(l + STRLEN(str2) + 1L));
5325 if (dest != NULL)
5326 {
5327 STRCPY(dest, str1);
5328 STRCPY(dest + l, str2);
5329 }
5330 return dest;
5331}
Bram Moolenaard6754642005-01-17 22:18:45 +00005332
Bram Moolenaar071d4272004-06-13 20:20:40 +00005333/*
5334 * Add a path separator to a file name, unless it already ends in a path
5335 * separator.
5336 */
5337 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005338add_pathsep(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005339{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005340 if (*p != NUL && !after_pathsep(p, p + STRLEN(p)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005341 STRCAT(p, PATHSEPSTR);
5342}
5343
5344/*
5345 * FullName_save - Make an allocated copy of a full file name.
5346 * Returns NULL when out of memory.
5347 */
5348 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005349FullName_save(
5350 char_u *fname,
5351 int force) /* force expansion, even when it already looks
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02005352 * like a full path name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005353{
5354 char_u *buf;
5355 char_u *new_fname = NULL;
5356
5357 if (fname == NULL)
5358 return NULL;
5359
5360 buf = alloc((unsigned)MAXPATHL);
5361 if (buf != NULL)
5362 {
5363 if (vim_FullName(fname, buf, MAXPATHL, force) != FAIL)
5364 new_fname = vim_strsave(buf);
5365 else
5366 new_fname = vim_strsave(fname);
5367 vim_free(buf);
5368 }
5369 return new_fname;
5370}
5371
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005373prepare_to_exit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005374{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005375#if defined(SIGHUP) && defined(SIG_IGN)
5376 /* Ignore SIGHUP, because a dropped connection causes a read error, which
5377 * makes Vim exit and then handling SIGHUP causes various reentrance
5378 * problems. */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00005379 signal(SIGHUP, SIG_IGN);
5380#endif
5381
Bram Moolenaar071d4272004-06-13 20:20:40 +00005382#ifdef FEAT_GUI
5383 if (gui.in_use)
5384 {
5385 gui.dying = TRUE;
5386 out_trash(); /* trash any pending output */
5387 }
5388 else
5389#endif
5390 {
5391 windgoto((int)Rows - 1, 0);
5392
5393 /*
5394 * Switch terminal mode back now, so messages end up on the "normal"
5395 * screen (if there are two screens).
5396 */
5397 settmode(TMODE_COOK);
Bram Moolenaarcea912a2016-10-12 14:20:24 +02005398 stoptermcap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005399 out_flush();
5400 }
5401}
5402
5403/*
5404 * Preserve files and exit.
5405 * When called IObuff must contain a message.
Bram Moolenaarbec9c202013-09-05 21:41:39 +02005406 * NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe
5407 * functions, such as allocating memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005408 */
5409 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005410preserve_exit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005411{
5412 buf_T *buf;
5413
5414 prepare_to_exit();
5415
Bram Moolenaar4770d092006-01-12 23:22:24 +00005416 /* Setting this will prevent free() calls. That avoids calling free()
5417 * recursively when free() was invoked with a bad pointer. */
5418 really_exiting = TRUE;
5419
Bram Moolenaar071d4272004-06-13 20:20:40 +00005420 out_str(IObuff);
5421 screen_start(); /* don't know where cursor is now */
5422 out_flush();
5423
5424 ml_close_notmod(); /* close all not-modified buffers */
5425
Bram Moolenaar29323592016-07-24 22:04:11 +02005426 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005427 {
5428 if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
5429 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02005430 OUT_STR("Vim: preserving files...\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005431 screen_start(); /* don't know where cursor is now */
5432 out_flush();
5433 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
5434 break;
5435 }
5436 }
5437
5438 ml_close_all(FALSE); /* close all memfiles, without deleting */
5439
Bram Moolenaarbec9c202013-09-05 21:41:39 +02005440 OUT_STR("Vim: Finished.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005441
5442 getout(1);
5443}
5444
5445/*
5446 * return TRUE if "fname" exists.
5447 */
5448 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005449vim_fexists(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005450{
Bram Moolenaar8767f522016-07-01 17:17:39 +02005451 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005452
5453 if (mch_stat((char *)fname, &st))
5454 return FALSE;
5455 return TRUE;
5456}
5457
5458/*
5459 * Check for CTRL-C pressed, but only once in a while.
5460 * Should be used instead of ui_breakcheck() for functions that check for
5461 * each line in the file. Calling ui_breakcheck() each time takes too much
5462 * time, because it can be a system call.
5463 */
5464
5465#ifndef BREAKCHECK_SKIP
5466# ifdef FEAT_GUI /* assume the GUI only runs on fast computers */
5467# define BREAKCHECK_SKIP 200
5468# else
5469# define BREAKCHECK_SKIP 32
5470# endif
5471#endif
5472
5473static int breakcheck_count = 0;
5474
5475 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005476line_breakcheck(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005477{
5478 if (++breakcheck_count >= BREAKCHECK_SKIP)
5479 {
5480 breakcheck_count = 0;
5481 ui_breakcheck();
5482 }
5483}
5484
5485/*
5486 * Like line_breakcheck() but check 10 times less often.
5487 */
5488 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005489fast_breakcheck(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005490{
5491 if (++breakcheck_count >= BREAKCHECK_SKIP * 10)
5492 {
5493 breakcheck_count = 0;
5494 ui_breakcheck();
5495 }
5496}
5497
5498/*
Bram Moolenaard7834d32009-12-02 16:14:36 +00005499 * Invoke expand_wildcards() for one pattern.
5500 * Expand items like "%:h" before the expansion.
5501 * Returns OK or FAIL.
5502 */
5503 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005504expand_wildcards_eval(
5505 char_u **pat, /* pointer to input pattern */
5506 int *num_file, /* resulting number of files */
5507 char_u ***file, /* array of resulting files */
5508 int flags) /* EW_DIR, etc. */
Bram Moolenaard7834d32009-12-02 16:14:36 +00005509{
5510 int ret = FAIL;
5511 char_u *eval_pat = NULL;
5512 char_u *exp_pat = *pat;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005513 char *ignored_msg;
Bram Moolenaard7834d32009-12-02 16:14:36 +00005514 int usedlen;
5515
5516 if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<')
5517 {
5518 ++emsg_off;
5519 eval_pat = eval_vars(exp_pat, exp_pat, &usedlen,
5520 NULL, &ignored_msg, NULL);
5521 --emsg_off;
5522 if (eval_pat != NULL)
5523 exp_pat = concat_str(eval_pat, exp_pat + usedlen);
5524 }
5525
5526 if (exp_pat != NULL)
5527 ret = expand_wildcards(1, &exp_pat, num_file, file, flags);
5528
5529 if (eval_pat != NULL)
5530 {
5531 vim_free(exp_pat);
5532 vim_free(eval_pat);
5533 }
5534
5535 return ret;
5536}
5537
5538/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005539 * Expand wildcards. Calls gen_expand_wildcards() and removes files matching
5540 * 'wildignore'.
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005541 * Returns OK or FAIL. When FAIL then "num_files" won't be set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005542 */
5543 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005544expand_wildcards(
5545 int num_pat, /* number of input patterns */
5546 char_u **pat, /* array of input patterns */
5547 int *num_files, /* resulting number of files */
5548 char_u ***files, /* array of resulting files */
5549 int flags) /* EW_DIR, etc. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005550{
5551 int retval;
5552 int i, j;
5553 char_u *p;
5554 int non_suf_match; /* number without matching suffix */
5555
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005556 retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005557
5558 /* When keeping all matches, return here */
Bram Moolenaar9e193ac2010-07-19 23:11:27 +02005559 if ((flags & EW_KEEPALL) || retval == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005560 return retval;
5561
5562#ifdef FEAT_WILDIGN
5563 /*
5564 * Remove names that match 'wildignore'.
5565 */
5566 if (*p_wig)
5567 {
5568 char_u *ffname;
5569
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005570 /* check all files in (*files)[] */
5571 for (i = 0; i < *num_files; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005572 {
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005573 ffname = FullName_save((*files)[i], FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574 if (ffname == NULL) /* out of memory */
5575 break;
5576# ifdef VMS
5577 vms_remove_version(ffname);
5578# endif
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005579 if (match_file_list(p_wig, (*files)[i], ffname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005580 {
Bram Moolenaar187a4f22017-02-23 17:07:14 +01005581 /* remove this matching file from the list */
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005582 vim_free((*files)[i]);
5583 for (j = i; j + 1 < *num_files; ++j)
5584 (*files)[j] = (*files)[j + 1];
5585 --*num_files;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005586 --i;
5587 }
5588 vim_free(ffname);
5589 }
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005590
5591 /* If the number of matches is now zero, we fail. */
5592 if (*num_files == 0)
5593 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01005594 VIM_CLEAR(*files);
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005595 return FAIL;
5596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005597 }
5598#endif
5599
5600 /*
5601 * Move the names where 'suffixes' match to the end.
5602 */
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005603 if (*num_files > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005604 {
5605 non_suf_match = 0;
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005606 for (i = 0; i < *num_files; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005607 {
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005608 if (!match_suffix((*files)[i]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005609 {
5610 /*
5611 * Move the name without matching suffix to the front
5612 * of the list.
5613 */
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005614 p = (*files)[i];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005615 for (j = i; j > non_suf_match; --j)
Bram Moolenaar7b256fe2015-09-15 19:05:59 +02005616 (*files)[j] = (*files)[j - 1];
5617 (*files)[non_suf_match++] = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005618 }
5619 }
5620 }
5621
5622 return retval;
5623}
5624
5625/*
5626 * Return TRUE if "fname" matches with an entry in 'suffixes'.
5627 */
5628 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005629match_suffix(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005630{
5631 int fnamelen, setsuflen;
5632 char_u *setsuf;
5633#define MAXSUFLEN 30 /* maximum length of a file suffix */
5634 char_u suf_buf[MAXSUFLEN];
5635
5636 fnamelen = (int)STRLEN(fname);
5637 setsuflen = 0;
5638 for (setsuf = p_su; *setsuf; )
5639 {
5640 setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,");
Bram Moolenaar055a2ba2009-07-14 19:40:21 +00005641 if (setsuflen == 0)
5642 {
5643 char_u *tail = gettail(fname);
5644
5645 /* empty entry: match name without a '.' */
5646 if (vim_strchr(tail, '.') == NULL)
5647 {
5648 setsuflen = 1;
5649 break;
5650 }
5651 }
5652 else
5653 {
5654 if (fnamelen >= setsuflen
5655 && fnamencmp(suf_buf, fname + fnamelen - setsuflen,
5656 (size_t)setsuflen) == 0)
5657 break;
5658 setsuflen = 0;
5659 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660 }
5661 return (setsuflen != 0);
5662}
5663
5664#if !defined(NO_EXPANDPATH) || defined(PROTO)
5665
5666# ifdef VIM_BACKTICK
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01005667static int vim_backtick(char_u *p);
5668static int expand_backtick(garray_T *gap, char_u *pat, int flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005669# endif
5670
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005671# if defined(WIN3264)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005672/*
5673 * File name expansion code for MS-DOS, Win16 and Win32. It's here because
5674 * it's shared between these systems.
5675 */
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005676# if defined(PROTO)
5677# define _cdecl
Bram Moolenaar071d4272004-06-13 20:20:40 +00005678# else
5679# ifdef __BORLANDC__
5680# define _cdecl _RTLENTRYF
5681# endif
5682# endif
5683
5684/*
5685 * comparison function for qsort in dos_expandpath()
5686 */
5687 static int _cdecl
5688pstrcmp(const void *a, const void *b)
5689{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005690 return (pathcmp(*(char **)a, *(char **)b, -1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691}
5692
Bram Moolenaar071d4272004-06-13 20:20:40 +00005693/*
Bram Moolenaar231334e2005-07-25 20:46:57 +00005694 * Recursively expand one path component into all matching files and/or
5695 * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696 * Return the number of matches found.
5697 * "path" has backslashes before chars that are not to be expanded, starting
5698 * at "path[wildoff]".
Bram Moolenaar231334e2005-07-25 20:46:57 +00005699 * Return the number of matches found.
5700 * NOTE: much of this is identical to unix_expandpath(), keep in sync!
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701 */
5702 static int
5703dos_expandpath(
5704 garray_T *gap,
5705 char_u *path,
5706 int wildoff,
Bram Moolenaar231334e2005-07-25 20:46:57 +00005707 int flags, /* EW_* flags */
Bram Moolenaar25394022007-05-10 19:06:20 +00005708 int didstar) /* expanded "**" once already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005709{
Bram Moolenaar231334e2005-07-25 20:46:57 +00005710 char_u *buf;
5711 char_u *path_end;
5712 char_u *p, *s, *e;
5713 int start_len = gap->ga_len;
5714 char_u *pat;
5715 regmatch_T regmatch;
5716 int starts_with_dot;
5717 int matches;
5718 int len;
5719 int starstar = FALSE;
5720 static int stardepth = 0; /* depth for "**" expansion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005721 WIN32_FIND_DATA fb;
5722 HANDLE hFind = (HANDLE)0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005723 WIN32_FIND_DATAW wfb;
5724 WCHAR *wn = NULL; /* UCS-2 name, NULL when not used. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005725 char_u *matchname;
Bram Moolenaar231334e2005-07-25 20:46:57 +00005726 int ok;
5727
5728 /* Expanding "**" may take a long time, check for CTRL-C. */
5729 if (stardepth > 0)
5730 {
5731 ui_breakcheck();
5732 if (got_int)
5733 return 0;
5734 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01005736 // Make room for file name. When doing encoding conversion the actual
5737 // length may be quite a bit longer, thus use the maximum possible length.
Bram Moolenaar7314efd2015-10-31 15:32:52 +01005738 buf = alloc((int)MAXPATHL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005739 if (buf == NULL)
5740 return 0;
5741
5742 /*
5743 * Find the first part in the path name that contains a wildcard or a ~1.
5744 * Copy it into buf, including the preceding characters.
5745 */
5746 p = buf;
5747 s = buf;
5748 e = NULL;
5749 path_end = path;
5750 while (*path_end != NUL)
5751 {
5752 /* May ignore a wildcard that has a backslash before it; it will
5753 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
5754 if (path_end >= path + wildoff && rem_backslash(path_end))
5755 *p++ = *path_end++;
5756 else if (*path_end == '\\' || *path_end == ':' || *path_end == '/')
5757 {
5758 if (e != NULL)
5759 break;
5760 s = p + 1;
5761 }
5762 else if (path_end >= path + wildoff
5763 && vim_strchr((char_u *)"*?[~", *path_end) != NULL)
5764 e = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005765 if (has_mbyte)
5766 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005767 len = (*mb_ptr2len)(path_end);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005768 STRNCPY(p, path_end, len);
5769 p += len;
5770 path_end += len;
5771 }
5772 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005773 *p++ = *path_end++;
5774 }
5775 e = p;
5776 *e = NUL;
5777
5778 /* now we have one wildcard component between s and e */
5779 /* Remove backslashes between "wildoff" and the start of the wildcard
5780 * component. */
5781 for (p = buf + wildoff; p < s; ++p)
5782 if (rem_backslash(p))
5783 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005784 STRMOVE(p, p + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005785 --e;
5786 --s;
5787 }
5788
Bram Moolenaar231334e2005-07-25 20:46:57 +00005789 /* Check for "**" between "s" and "e". */
5790 for (p = s; p < e; ++p)
5791 if (p[0] == '*' && p[1] == '*')
5792 starstar = TRUE;
5793
Bram Moolenaard82103e2016-01-17 17:04:05 +01005794 starts_with_dot = *s == '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00005795 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
5796 if (pat == NULL)
5797 {
5798 vim_free(buf);
5799 return 0;
5800 }
5801
5802 /* compile the regexp into a program */
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01005803 if (flags & (EW_NOERROR | EW_NOTWILD))
Bram Moolenaarb5609832011-07-20 15:04:58 +02005804 ++emsg_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005805 regmatch.rm_ic = TRUE; /* Always ignore case */
5806 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01005807 if (flags & (EW_NOERROR | EW_NOTWILD))
Bram Moolenaarb5609832011-07-20 15:04:58 +02005808 --emsg_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005809 vim_free(pat);
5810
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01005811 if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005812 {
5813 vim_free(buf);
5814 return 0;
5815 }
5816
5817 /* remember the pattern or file name being looked for */
5818 matchname = vim_strsave(s);
5819
Bram Moolenaar231334e2005-07-25 20:46:57 +00005820 /* If "**" is by itself, this is the first time we encounter it and more
5821 * is following then find matches without any directory. */
5822 if (!didstar && stardepth < 100 && starstar && e - s == 2
5823 && *path_end == '/')
5824 {
5825 STRCPY(s, path_end + 1);
5826 ++stardepth;
5827 (void)dos_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
5828 --stardepth;
5829 }
5830
Bram Moolenaar071d4272004-06-13 20:20:40 +00005831 /* Scan all files in the directory with "dir/ *.*" */
5832 STRCPY(s, "*.*");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005833 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
5834 {
5835 /* The active codepage differs from 'encoding'. Attempt using the
5836 * wide function. If it fails because it is not implemented fall back
5837 * to the non-wide version (for Windows 98) */
Bram Moolenaar36f692d2008-11-20 16:10:17 +00005838 wn = enc_to_utf16(buf, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 if (wn != NULL)
5840 {
5841 hFind = FindFirstFileW(wn, &wfb);
5842 if (hFind == INVALID_HANDLE_VALUE
5843 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
Bram Moolenaard23a8232018-02-10 18:45:26 +01005844 VIM_CLEAR(wn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845 }
5846 }
5847
5848 if (wn == NULL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005849 hFind = FindFirstFile((LPCSTR)buf, &fb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005850 ok = (hFind != INVALID_HANDLE_VALUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005851
5852 while (ok)
5853 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005854 if (wn != NULL)
Bram Moolenaar36f692d2008-11-20 16:10:17 +00005855 p = utf16_to_enc(wfb.cFileName, NULL); /* p is allocated here */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005856 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005857 p = (char_u *)fb.cFileName;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005858 /* Ignore entries starting with a dot, unless when asked for. Accept
5859 * all entries found with "matchname". */
Bram Moolenaard82103e2016-01-17 17:04:05 +01005860 if ((p[0] != '.' || starts_with_dot
5861 || ((flags & EW_DODOT)
5862 && p[1] != NUL && (p[1] != '.' || p[2] != NUL)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863 && (matchname == NULL
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01005864 || (regmatch.regprog != NULL
5865 && vim_regexec(&regmatch, p, (colnr_T)0))
Bram Moolenaar0b573a52011-07-27 17:31:47 +02005866 || ((flags & EW_NOTWILD)
5867 && fnamencmp(path + (s - buf), p, e - s) == 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005869 STRCPY(s, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005870 len = (int)STRLEN(buf);
Bram Moolenaar231334e2005-07-25 20:46:57 +00005871
5872 if (starstar && stardepth < 100)
5873 {
5874 /* For "**" in the pattern first go deeper in the tree to
5875 * find matches. */
5876 STRCPY(buf + len, "/**");
5877 STRCPY(buf + len + 3, path_end);
5878 ++stardepth;
5879 (void)dos_expandpath(gap, buf, len + 1, flags, TRUE);
5880 --stardepth;
5881 }
5882
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883 STRCPY(buf + len, path_end);
5884 if (mch_has_exp_wildcard(path_end))
5885 {
5886 /* need to expand another component of the path */
5887 /* remove backslashes for the remaining components only */
Bram Moolenaar231334e2005-07-25 20:46:57 +00005888 (void)dos_expandpath(gap, buf, len + 1, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005889 }
5890 else
5891 {
5892 /* no more wildcards, check if there is a match */
5893 /* remove backslashes for the remaining components only */
5894 if (*path_end != 0)
5895 backslash_halve(buf + len + 1);
5896 if (mch_getperm(buf) >= 0) /* add existing file */
5897 addfile(gap, buf, flags);
5898 }
5899 }
5900
Bram Moolenaar071d4272004-06-13 20:20:40 +00005901 if (wn != NULL)
5902 {
5903 vim_free(p);
5904 ok = FindNextFileW(hFind, &wfb);
5905 }
5906 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005907 ok = FindNextFile(hFind, &fb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005908
5909 /* If no more matches and no match was used, try expanding the name
5910 * itself. Finds the long name of a short filename. */
5911 if (!ok && matchname != NULL && gap->ga_len == start_len)
5912 {
5913 STRCPY(s, matchname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005914 FindClose(hFind);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005915 if (wn != NULL)
5916 {
5917 vim_free(wn);
Bram Moolenaar36f692d2008-11-20 16:10:17 +00005918 wn = enc_to_utf16(buf, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919 if (wn != NULL)
5920 hFind = FindFirstFileW(wn, &wfb);
5921 }
5922 if (wn == NULL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005923 hFind = FindFirstFile((LPCSTR)buf, &fb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005924 ok = (hFind != INVALID_HANDLE_VALUE);
Bram Moolenaard23a8232018-02-10 18:45:26 +01005925 VIM_CLEAR(matchname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005926 }
5927 }
5928
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929 FindClose(hFind);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005930 vim_free(wn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005931 vim_free(buf);
Bram Moolenaar473de612013-06-08 18:19:48 +02005932 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005933 vim_free(matchname);
5934
5935 matches = gap->ga_len - start_len;
5936 if (matches > 0)
5937 qsort(((char_u **)gap->ga_data) + start_len, (size_t)matches,
5938 sizeof(char_u *), pstrcmp);
5939 return matches;
5940}
5941
5942 int
5943mch_expandpath(
5944 garray_T *gap,
5945 char_u *path,
5946 int flags) /* EW_* flags */
5947{
Bram Moolenaar231334e2005-07-25 20:46:57 +00005948 return dos_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005949}
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005950# endif /* WIN3264 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005951
Bram Moolenaar231334e2005-07-25 20:46:57 +00005952#if (defined(UNIX) && !defined(VMS)) || defined(USE_UNIXFILENAME) \
5953 || defined(PROTO)
5954/*
5955 * Unix style wildcard expansion code.
5956 * It's here because it's used both for Unix and Mac.
5957 */
Bram Moolenaar231334e2005-07-25 20:46:57 +00005958 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005959pstrcmp(const void *a, const void *b)
Bram Moolenaar231334e2005-07-25 20:46:57 +00005960{
5961 return (pathcmp(*(char **)a, *(char **)b, -1));
5962}
5963
5964/*
5965 * Recursively expand one path component into all matching files and/or
5966 * directories. Adds matches to "gap". Handles "*", "?", "[a-z]", "**", etc.
5967 * "path" has backslashes before chars that are not to be expanded, starting
5968 * at "path + wildoff".
5969 * Return the number of matches found.
5970 * NOTE: much of this is identical to dos_expandpath(), keep in sync!
5971 */
5972 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005973unix_expandpath(
5974 garray_T *gap,
5975 char_u *path,
5976 int wildoff,
5977 int flags, /* EW_* flags */
5978 int didstar) /* expanded "**" once already */
Bram Moolenaar231334e2005-07-25 20:46:57 +00005979{
5980 char_u *buf;
5981 char_u *path_end;
5982 char_u *p, *s, *e;
5983 int start_len = gap->ga_len;
5984 char_u *pat;
5985 regmatch_T regmatch;
5986 int starts_with_dot;
5987 int matches;
5988 int len;
5989 int starstar = FALSE;
5990 static int stardepth = 0; /* depth for "**" expansion */
5991
5992 DIR *dirp;
5993 struct dirent *dp;
5994
5995 /* Expanding "**" may take a long time, check for CTRL-C. */
5996 if (stardepth > 0)
5997 {
5998 ui_breakcheck();
5999 if (got_int)
6000 return 0;
6001 }
6002
6003 /* make room for file name */
6004 buf = alloc((int)STRLEN(path) + BASENAMELEN + 5);
6005 if (buf == NULL)
6006 return 0;
6007
6008 /*
6009 * Find the first part in the path name that contains a wildcard.
Bram Moolenaar2d0b92f2012-04-30 21:09:43 +02006010 * When EW_ICASE is set every letter is considered to be a wildcard.
Bram Moolenaar231334e2005-07-25 20:46:57 +00006011 * Copy it into "buf", including the preceding characters.
6012 */
6013 p = buf;
6014 s = buf;
6015 e = NULL;
6016 path_end = path;
6017 while (*path_end != NUL)
6018 {
6019 /* May ignore a wildcard that has a backslash before it; it will
6020 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
6021 if (path_end >= path + wildoff && rem_backslash(path_end))
6022 *p++ = *path_end++;
6023 else if (*path_end == '/')
6024 {
6025 if (e != NULL)
6026 break;
6027 s = p + 1;
6028 }
6029 else if (path_end >= path + wildoff
Bram Moolenaar2d0b92f2012-04-30 21:09:43 +02006030 && (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01006031 || (!p_fic && (flags & EW_ICASE)
6032 && isalpha(PTR2CHAR(path_end)))))
Bram Moolenaar231334e2005-07-25 20:46:57 +00006033 e = p;
Bram Moolenaar231334e2005-07-25 20:46:57 +00006034 if (has_mbyte)
6035 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006036 len = (*mb_ptr2len)(path_end);
Bram Moolenaar231334e2005-07-25 20:46:57 +00006037 STRNCPY(p, path_end, len);
6038 p += len;
6039 path_end += len;
6040 }
6041 else
Bram Moolenaar231334e2005-07-25 20:46:57 +00006042 *p++ = *path_end++;
6043 }
6044 e = p;
6045 *e = NUL;
6046
Bram Moolenaar0b573a52011-07-27 17:31:47 +02006047 /* Now we have one wildcard component between "s" and "e". */
Bram Moolenaar231334e2005-07-25 20:46:57 +00006048 /* Remove backslashes between "wildoff" and the start of the wildcard
6049 * component. */
6050 for (p = buf + wildoff; p < s; ++p)
6051 if (rem_backslash(p))
6052 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00006053 STRMOVE(p, p + 1);
Bram Moolenaar231334e2005-07-25 20:46:57 +00006054 --e;
6055 --s;
6056 }
6057
6058 /* Check for "**" between "s" and "e". */
6059 for (p = s; p < e; ++p)
6060 if (p[0] == '*' && p[1] == '*')
6061 starstar = TRUE;
6062
6063 /* convert the file pattern to a regexp pattern */
Bram Moolenaard82103e2016-01-17 17:04:05 +01006064 starts_with_dot = *s == '.';
Bram Moolenaar231334e2005-07-25 20:46:57 +00006065 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
6066 if (pat == NULL)
6067 {
6068 vim_free(buf);
6069 return 0;
6070 }
6071
6072 /* compile the regexp into a program */
Bram Moolenaar94950a92010-12-02 16:01:29 +01006073 if (flags & EW_ICASE)
6074 regmatch.rm_ic = TRUE; /* 'wildignorecase' set */
6075 else
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01006076 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01006077 if (flags & (EW_NOERROR | EW_NOTWILD))
6078 ++emsg_silent;
Bram Moolenaar231334e2005-07-25 20:46:57 +00006079 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01006080 if (flags & (EW_NOERROR | EW_NOTWILD))
6081 --emsg_silent;
Bram Moolenaar231334e2005-07-25 20:46:57 +00006082 vim_free(pat);
6083
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01006084 if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0)
Bram Moolenaar231334e2005-07-25 20:46:57 +00006085 {
6086 vim_free(buf);
6087 return 0;
6088 }
6089
6090 /* If "**" is by itself, this is the first time we encounter it and more
6091 * is following then find matches without any directory. */
6092 if (!didstar && stardepth < 100 && starstar && e - s == 2
6093 && *path_end == '/')
6094 {
6095 STRCPY(s, path_end + 1);
6096 ++stardepth;
6097 (void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE);
6098 --stardepth;
6099 }
6100
6101 /* open the directory for scanning */
6102 *s = NUL;
6103 dirp = opendir(*buf == NUL ? "." : (char *)buf);
6104
6105 /* Find all matching entries */
6106 if (dirp != NULL)
6107 {
6108 for (;;)
6109 {
6110 dp = readdir(dirp);
6111 if (dp == NULL)
6112 break;
Bram Moolenaard82103e2016-01-17 17:04:05 +01006113 if ((dp->d_name[0] != '.' || starts_with_dot
6114 || ((flags & EW_DODOT)
6115 && dp->d_name[1] != NUL
6116 && (dp->d_name[1] != '.' || dp->d_name[2] != NUL)))
Bram Moolenaar1f5965b2012-01-10 18:37:58 +01006117 && ((regmatch.regprog != NULL && vim_regexec(&regmatch,
6118 (char_u *)dp->d_name, (colnr_T)0))
Bram Moolenaar0b573a52011-07-27 17:31:47 +02006119 || ((flags & EW_NOTWILD)
6120 && fnamencmp(path + (s - buf), dp->d_name, e - s) == 0)))
Bram Moolenaar231334e2005-07-25 20:46:57 +00006121 {
6122 STRCPY(s, dp->d_name);
6123 len = STRLEN(buf);
6124
6125 if (starstar && stardepth < 100)
6126 {
6127 /* For "**" in the pattern first go deeper in the tree to
6128 * find matches. */
6129 STRCPY(buf + len, "/**");
6130 STRCPY(buf + len + 3, path_end);
6131 ++stardepth;
6132 (void)unix_expandpath(gap, buf, len + 1, flags, TRUE);
6133 --stardepth;
6134 }
6135
6136 STRCPY(buf + len, path_end);
6137 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
6138 {
6139 /* need to expand another component of the path */
6140 /* remove backslashes for the remaining components only */
6141 (void)unix_expandpath(gap, buf, len + 1, flags, FALSE);
6142 }
6143 else
6144 {
Bram Moolenaar8767f522016-07-01 17:17:39 +02006145 stat_T sb;
Bram Moolenaard8b77f72015-03-05 21:21:19 +01006146
Bram Moolenaar231334e2005-07-25 20:46:57 +00006147 /* no more wildcards, check if there is a match */
6148 /* remove backslashes for the remaining components only */
6149 if (*path_end != NUL)
6150 backslash_halve(buf + len + 1);
Bram Moolenaard8b77f72015-03-05 21:21:19 +01006151 /* add existing file or symbolic link */
Bram Moolenaarab11a592015-03-06 22:00:11 +01006152 if ((flags & EW_ALLLINKS) ? mch_lstat((char *)buf, &sb) >= 0
Bram Moolenaard8b77f72015-03-05 21:21:19 +01006153 : mch_getperm(buf) >= 0)
Bram Moolenaar231334e2005-07-25 20:46:57 +00006154 {
Bram Moolenaar95e9b492006-03-15 23:04:43 +00006155#ifdef MACOS_CONVERT
Bram Moolenaar231334e2005-07-25 20:46:57 +00006156 size_t precomp_len = STRLEN(buf)+1;
6157 char_u *precomp_buf =
6158 mac_precompose_path(buf, precomp_len, &precomp_len);
Bram Moolenaar95e9b492006-03-15 23:04:43 +00006159
Bram Moolenaar231334e2005-07-25 20:46:57 +00006160 if (precomp_buf)
6161 {
6162 mch_memmove(buf, precomp_buf, precomp_len);
6163 vim_free(precomp_buf);
6164 }
6165#endif
6166 addfile(gap, buf, flags);
6167 }
6168 }
6169 }
6170 }
6171
6172 closedir(dirp);
6173 }
6174
6175 vim_free(buf);
Bram Moolenaar473de612013-06-08 18:19:48 +02006176 vim_regfree(regmatch.regprog);
Bram Moolenaar231334e2005-07-25 20:46:57 +00006177
6178 matches = gap->ga_len - start_len;
6179 if (matches > 0)
6180 qsort(((char_u **)gap->ga_data) + start_len, matches,
6181 sizeof(char_u *), pstrcmp);
6182 return matches;
6183}
6184#endif
6185
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006186#if defined(FEAT_SEARCHPATH)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006187/*
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006188 * Moves "*psep" back to the previous path separator in "path".
6189 * Returns FAIL is "*psep" ends up at the beginning of "path".
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006190 */
6191 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006192find_previous_pathsep(char_u *path, char_u **psep)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006193{
6194 /* skip the current separator */
6195 if (*psep > path && vim_ispathsep(**psep))
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006196 --*psep;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006197
6198 /* find the previous separator */
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006199 while (*psep > path)
6200 {
6201 if (vim_ispathsep(**psep))
6202 return OK;
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006203 MB_PTR_BACK(path, *psep);
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006204 }
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006205
6206 return FAIL;
6207}
6208
6209/*
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006210 * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap".
6211 * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]".
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006212 */
6213 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006214is_unique(char_u *maybe_unique, garray_T *gap, int i)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006215{
6216 int j;
6217 int candidate_len;
6218 int other_path_len;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006219 char_u **other_paths = (char_u **)gap->ga_data;
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006220 char_u *rival;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006221
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006222 for (j = 0; j < gap->ga_len; j++)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006223 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006224 if (j == i)
Bram Moolenaar162bd912010-07-28 22:29:10 +02006225 continue; /* don't compare it with itself */
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006226
Bram Moolenaar624c7aa2010-07-16 20:38:52 +02006227 candidate_len = (int)STRLEN(maybe_unique);
6228 other_path_len = (int)STRLEN(other_paths[j]);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006229 if (other_path_len < candidate_len)
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006230 continue; /* it's different when it's shorter */
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006231
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006232 rival = other_paths[j] + other_path_len - candidate_len;
Bram Moolenaarda9836c2010-08-16 21:53:27 +02006233 if (fnamecmp(maybe_unique, rival) == 0
6234 && (rival == other_paths[j] || vim_ispathsep(*(rival - 1))))
Bram Moolenaar162bd912010-07-28 22:29:10 +02006235 return FALSE; /* match */
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006236 }
6237
Bram Moolenaar162bd912010-07-28 22:29:10 +02006238 return TRUE; /* no match found */
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006239}
6240
6241/*
Bram Moolenaar1a509df2010-08-01 17:59:57 +02006242 * Split the 'path' option into an array of strings in garray_T. Relative
Bram Moolenaar162bd912010-07-28 22:29:10 +02006243 * paths are expanded to their equivalent fullpath. This includes the "."
6244 * (relative to current buffer directory) and empty path (relative to current
6245 * directory) notations.
6246 *
6247 * TODO: handle upward search (;) and path limiter (**N) notations by
6248 * expanding each into their equivalent path(s).
6249 */
6250 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006251expand_path_option(char_u *curdir, garray_T *gap)
Bram Moolenaar162bd912010-07-28 22:29:10 +02006252{
6253 char_u *path_option = *curbuf->b_p_path == NUL
6254 ? p_path : curbuf->b_p_path;
6255 char_u *buf;
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006256 char_u *p;
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006257 int len;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006258
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006259 if ((buf = alloc((int)MAXPATHL)) == NULL)
Bram Moolenaar162bd912010-07-28 22:29:10 +02006260 return;
6261
6262 while (*path_option != NUL)
6263 {
6264 copy_option_part(&path_option, buf, MAXPATHL, " ,");
6265
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006266 if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1])))
Bram Moolenaar162bd912010-07-28 22:29:10 +02006267 {
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006268 /* Relative to current buffer:
6269 * "/path/file" + "." -> "/path/"
6270 * "/path/file" + "./subdir" -> "/path/subdir" */
Bram Moolenaar162bd912010-07-28 22:29:10 +02006271 if (curbuf->b_ffname == NULL)
6272 continue;
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006273 p = gettail(curbuf->b_ffname);
6274 len = (int)(p - curbuf->b_ffname);
6275 if (len + (int)STRLEN(buf) >= MAXPATHL)
6276 continue;
6277 if (buf[1] == NUL)
6278 buf[len] = NUL;
6279 else
6280 STRMOVE(buf + len, buf + 2);
6281 mch_memmove(buf, curbuf->b_ffname, len);
6282 simplify_filename(buf);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006283 }
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006284 else if (buf[0] == NUL)
6285 /* relative to current directory */
Bram Moolenaar162bd912010-07-28 22:29:10 +02006286 STRCPY(buf, curdir);
Bram Moolenaar84f888a2010-08-05 21:40:16 +02006287 else if (path_with_url(buf))
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006288 /* URL can't be used here */
Bram Moolenaar84f888a2010-08-05 21:40:16 +02006289 continue;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006290 else if (!mch_isFullName(buf))
6291 {
6292 /* Expand relative path to their full path equivalent */
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006293 len = (int)STRLEN(curdir);
6294 if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
Bram Moolenaar162bd912010-07-28 22:29:10 +02006295 continue;
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006296 STRMOVE(buf + len + 1, buf);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006297 STRCPY(buf, curdir);
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006298 buf[len] = PATHSEP;
Bram Moolenaar57adda12010-08-03 22:11:29 +02006299 simplify_filename(buf);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006300 }
6301
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006302 if (ga_grow(gap, 1) == FAIL)
6303 break;
Bram Moolenaar811fe632013-04-24 17:34:20 +02006304
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006305# if defined(MSWIN)
Bram Moolenaar811fe632013-04-24 17:34:20 +02006306 /* Avoid the path ending in a backslash, it fails when a comma is
6307 * appended. */
Bram Moolenaar4e0d9742013-05-04 03:40:27 +02006308 len = (int)STRLEN(buf);
Bram Moolenaar811fe632013-04-24 17:34:20 +02006309 if (buf[len - 1] == '\\')
6310 buf[len - 1] = '/';
6311# endif
6312
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006313 p = vim_strsave(buf);
6314 if (p == NULL)
6315 break;
6316 ((char_u **)gap->ga_data)[gap->ga_len++] = p;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006317 }
6318
6319 vim_free(buf);
6320}
6321
6322/*
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006323 * Returns a pointer to the file or directory name in "fname" that matches the
6324 * longest path in "ga"p, or NULL if there is no match. For example:
Bram Moolenaar162bd912010-07-28 22:29:10 +02006325 *
6326 * path: /foo/bar/baz
6327 * fname: /foo/bar/baz/quux.txt
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006328 * returns: ^this
Bram Moolenaar162bd912010-07-28 22:29:10 +02006329 */
6330 static char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01006331get_path_cutoff(char_u *fname, garray_T *gap)
Bram Moolenaar162bd912010-07-28 22:29:10 +02006332{
6333 int i;
6334 int maxlen = 0;
6335 char_u **path_part = (char_u **)gap->ga_data;
6336 char_u *cutoff = NULL;
6337
6338 for (i = 0; i < gap->ga_len; i++)
6339 {
6340 int j = 0;
6341
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006342 while ((fname[j] == path_part[i][j]
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006343# if defined(MSWIN)
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006344 || (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j]))
6345#endif
6346 ) && fname[j] != NUL && path_part[i][j] != NUL)
Bram Moolenaar162bd912010-07-28 22:29:10 +02006347 j++;
6348 if (j > maxlen)
6349 {
6350 maxlen = j;
6351 cutoff = &fname[j];
6352 }
6353 }
6354
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006355 /* skip to the file or directory name */
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006356 if (cutoff != NULL)
Bram Moolenaar31710262010-08-13 13:36:15 +02006357 while (vim_ispathsep(*cutoff))
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006358 MB_PTR_ADV(cutoff);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006359
6360 return cutoff;
6361}
6362
6363/*
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006364 * Sorts, removes duplicates and modifies all the fullpath names in "gap" so
6365 * that they are unique with respect to each other while conserving the part
6366 * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len".
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006367 */
6368 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006369uniquefy_paths(garray_T *gap, char_u *pattern)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006370{
Bram Moolenaarcb9d45c2010-07-20 18:10:15 +02006371 int i;
6372 int len;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006373 char_u **fnames = (char_u **)gap->ga_data;
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006374 int sort_again = FALSE;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006375 char_u *pat;
6376 char_u *file_pattern;
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006377 char_u *curdir;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006378 regmatch_T regmatch;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006379 garray_T path_ga;
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006380 char_u **in_curdir = NULL;
6381 char_u *short_name;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006382
Bram Moolenaarcb9d45c2010-07-20 18:10:15 +02006383 remove_duplicates(gap);
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006384 ga_init2(&path_ga, (int)sizeof(char_u *), 1);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006385
6386 /*
6387 * We need to prepend a '*' at the beginning of file_pattern so that the
6388 * regex matches anywhere in the path. FIXME: is this valid for all
Bram Moolenaarb31e4382010-07-24 16:01:56 +02006389 * possible patterns?
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006390 */
Bram Moolenaar624c7aa2010-07-16 20:38:52 +02006391 len = (int)STRLEN(pattern);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006392 file_pattern = alloc(len + 2);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006393 if (file_pattern == NULL)
6394 return;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006395 file_pattern[0] = '*';
Bram Moolenaar162bd912010-07-28 22:29:10 +02006396 file_pattern[1] = NUL;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006397 STRCAT(file_pattern, pattern);
6398 pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
6399 vim_free(file_pattern);
Bram Moolenaarb31e4382010-07-24 16:01:56 +02006400 if (pat == NULL)
6401 return;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006402
Bram Moolenaarb31e4382010-07-24 16:01:56 +02006403 regmatch.rm_ic = TRUE; /* always ignore case */
6404 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6405 vim_free(pat);
6406 if (regmatch.regprog == NULL)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006407 return;
6408
Bram Moolenaar162bd912010-07-28 22:29:10 +02006409 if ((curdir = alloc((int)(MAXPATHL))) == NULL)
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006410 goto theend;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006411 mch_dirname(curdir, MAXPATHL);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006412 expand_path_option(curdir, &path_ga);
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006413
6414 in_curdir = (char_u **)alloc_clear(gap->ga_len * sizeof(char_u *));
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006415 if (in_curdir == NULL)
6416 goto theend;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006417
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006418 for (i = 0; i < gap->ga_len && !got_int; i++)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006419 {
Bram Moolenaar162bd912010-07-28 22:29:10 +02006420 char_u *path = fnames[i];
6421 int is_in_curdir;
Bram Moolenaar31710262010-08-13 13:36:15 +02006422 char_u *dir_end = gettail_dir(path);
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006423 char_u *pathsep_p;
6424 char_u *path_cutoff;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006425
Bram Moolenaar624c7aa2010-07-16 20:38:52 +02006426 len = (int)STRLEN(path);
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006427 is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
Bram Moolenaar162bd912010-07-28 22:29:10 +02006428 && curdir[dir_end - path] == NUL;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006429 if (is_in_curdir)
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006430 in_curdir[i] = vim_strsave(path);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006431
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006432 /* Shorten the filename while maintaining its uniqueness */
6433 path_cutoff = get_path_cutoff(path, &path_ga);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006434
Bram Moolenaar73d4e4c2016-08-27 21:55:13 +02006435 /* Don't assume all files can be reached without path when search
6436 * pattern starts with star star slash, so only remove path_cutoff
6437 * when possible. */
6438 if (pattern[0] == '*' && pattern[1] == '*'
6439 && vim_ispathsep_nocolon(pattern[2])
6440 && path_cutoff != NULL
6441 && vim_regexec(&regmatch, path_cutoff, (colnr_T)0)
6442 && is_unique(path_cutoff, gap, i))
6443 {
6444 sort_again = TRUE;
6445 mch_memmove(path, path_cutoff, STRLEN(path_cutoff) + 1);
6446 }
6447 else
6448 {
6449 /* Here all files can be reached without path, so get shortest
6450 * unique path. We start at the end of the path. */
6451 pathsep_p = path + len - 1;
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006452
Bram Moolenaar73d4e4c2016-08-27 21:55:13 +02006453 while (find_previous_pathsep(path, &pathsep_p))
6454 if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
6455 && is_unique(pathsep_p + 1, gap, i)
6456 && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
6457 {
6458 sort_again = TRUE;
6459 mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
6460 break;
6461 }
6462 }
Bram Moolenaar9bc040c2010-08-11 22:05:57 +02006463
6464 if (mch_isFullName(path))
6465 {
6466 /*
6467 * Last resort: shorten relative to curdir if possible.
6468 * 'possible' means:
6469 * 1. It is under the current directory.
6470 * 2. The result is actually shorter than the original.
6471 *
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006472 * Before curdir After
6473 * /foo/bar/file.txt /foo/bar ./file.txt
6474 * c:\foo\bar\file.txt c:\foo\bar .\file.txt
6475 * /file.txt / /file.txt
6476 * c:\file.txt c:\ .\file.txt
Bram Moolenaar9bc040c2010-08-11 22:05:57 +02006477 */
6478 short_name = shorten_fname(path, curdir);
Bram Moolenaar31710262010-08-13 13:36:15 +02006479 if (short_name != NULL && short_name > path + 1
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006480#if defined(MSWIN)
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006481 /* On windows,
Bram Moolenaar31710262010-08-13 13:36:15 +02006482 * shorten_fname("c:\a\a.txt", "c:\a\b")
Bram Moolenaar31710262010-08-13 13:36:15 +02006483 * returns "\a\a.txt", which is not really the short
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006484 * name, hence: */
Bram Moolenaar31710262010-08-13 13:36:15 +02006485 && !vim_ispathsep(*short_name)
6486#endif
6487 )
Bram Moolenaar9bc040c2010-08-11 22:05:57 +02006488 {
6489 STRCPY(path, ".");
6490 add_pathsep(path);
Bram Moolenaarcda000e2010-08-14 13:34:39 +02006491 STRMOVE(path + STRLEN(path), short_name);
Bram Moolenaar9bc040c2010-08-11 22:05:57 +02006492 }
6493 }
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006494 ui_breakcheck();
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006495 }
6496
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006497 /* Shorten filenames in /in/current/directory/{filename} */
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006498 for (i = 0; i < gap->ga_len && !got_int; i++)
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006499 {
6500 char_u *rel_path;
6501 char_u *path = in_curdir[i];
6502
6503 if (path == NULL)
6504 continue;
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006505
6506 /* If the {filename} is not unique, change it to ./{filename}.
6507 * Else reduce it to {filename} */
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006508 short_name = shorten_fname(path, curdir);
6509 if (short_name == NULL)
6510 short_name = path;
6511 if (is_unique(short_name, gap, i))
6512 {
6513 STRCPY(fnames[i], short_name);
6514 continue;
6515 }
6516
6517 rel_path = alloc((int)(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2));
6518 if (rel_path == NULL)
6519 goto theend;
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006520 STRCPY(rel_path, ".");
6521 add_pathsep(rel_path);
6522 STRCAT(rel_path, short_name);
6523
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006524 vim_free(fnames[i]);
6525 fnames[i] = rel_path;
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006526 sort_again = TRUE;
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006527 ui_breakcheck();
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006528 }
6529
Bram Moolenaar162bd912010-07-28 22:29:10 +02006530theend:
6531 vim_free(curdir);
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006532 if (in_curdir != NULL)
6533 {
6534 for (i = 0; i < gap->ga_len; i++)
6535 vim_free(in_curdir[i]);
6536 vim_free(in_curdir);
6537 }
Bram Moolenaar162bd912010-07-28 22:29:10 +02006538 ga_clear_strings(&path_ga);
Bram Moolenaar473de612013-06-08 18:19:48 +02006539 vim_regfree(regmatch.regprog);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006540
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006541 if (sort_again)
Bram Moolenaarcb9d45c2010-07-20 18:10:15 +02006542 remove_duplicates(gap);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006543}
6544
6545/*
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006546 * Calls globpath() with 'path' values for the given pattern and stores the
6547 * result in "gap".
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006548 * Returns the total number of matches.
6549 */
6550 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006551expand_in_path(
6552 garray_T *gap,
6553 char_u *pattern,
6554 int flags) /* EW_* flags */
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006555{
Bram Moolenaar162bd912010-07-28 22:29:10 +02006556 char_u *curdir;
6557 garray_T path_ga;
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006558 char_u *paths = NULL;
Bram Moolenaar8a37b032018-02-03 20:43:08 +01006559 int glob_flags = 0;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006560
Bram Moolenaar7f0f6212010-08-03 22:21:00 +02006561 if ((curdir = alloc((unsigned)MAXPATHL)) == NULL)
Bram Moolenaar162bd912010-07-28 22:29:10 +02006562 return 0;
6563 mch_dirname(curdir, MAXPATHL);
6564
Bram Moolenaar0be992e2010-08-12 21:50:51 +02006565 ga_init2(&path_ga, (int)sizeof(char_u *), 1);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006566 expand_path_option(curdir, &path_ga);
6567 vim_free(curdir);
Bram Moolenaar006d2b02010-08-04 12:39:44 +02006568 if (path_ga.ga_len == 0)
6569 return 0;
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006570
Bram Moolenaar1b1063a2014-05-07 18:35:30 +02006571 paths = ga_concat_strings(&path_ga, ",");
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006572 ga_clear_strings(&path_ga);
6573 if (paths == NULL)
Bram Moolenaar7f0f6212010-08-03 22:21:00 +02006574 return 0;
Bram Moolenaar162bd912010-07-28 22:29:10 +02006575
Bram Moolenaar8a37b032018-02-03 20:43:08 +01006576 if (flags & EW_ICASE)
6577 glob_flags |= WILD_ICASE;
6578 if (flags & EW_ADDSLASH)
6579 glob_flags |= WILD_ADD_SLASH;
6580 globpath(paths, pattern, gap, glob_flags);
Bram Moolenaar162bd912010-07-28 22:29:10 +02006581 vim_free(paths);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006582
Bram Moolenaarbdc975c2010-08-02 21:33:37 +02006583 return gap->ga_len;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006584}
6585#endif
6586
Bram Moolenaar1587a1e2010-07-29 20:59:59 +02006587#if defined(FEAT_SEARCHPATH) || defined(FEAT_CMDL_COMPL) || defined(PROTO)
6588/*
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006589 * Sort "gap" and remove duplicate entries. "gap" is expected to contain a
6590 * list of file names in allocated memory.
Bram Moolenaar1587a1e2010-07-29 20:59:59 +02006591 */
6592 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006593remove_duplicates(garray_T *gap)
Bram Moolenaar1587a1e2010-07-29 20:59:59 +02006594{
6595 int i;
6596 int j;
6597 char_u **fnames = (char_u **)gap->ga_data;
6598
Bram Moolenaardc685ab2010-08-13 21:16:49 +02006599 sort_strings(fnames, gap->ga_len);
Bram Moolenaar1587a1e2010-07-29 20:59:59 +02006600 for (i = gap->ga_len - 1; i > 0; --i)
6601 if (fnamecmp(fnames[i - 1], fnames[i]) == 0)
6602 {
6603 vim_free(fnames[i]);
6604 for (j = i + 1; j < gap->ga_len; ++j)
6605 fnames[j - 1] = fnames[j];
6606 --gap->ga_len;
6607 }
6608}
6609#endif
6610
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006611/*
6612 * Return TRUE if "p" contains what looks like an environment variable.
6613 * Allowing for escaping.
6614 */
6615 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006616has_env_var(char_u *p)
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006617{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006618 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006619 {
6620 if (*p == '\\' && p[1] != NUL)
6621 ++p;
6622 else if (vim_strchr((char_u *)
Bram Moolenaar48e330a2016-02-23 14:53:34 +01006623#if defined(MSWIN)
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006624 "$%"
6625#else
6626 "$"
6627#endif
6628 , *p) != NULL)
6629 return TRUE;
6630 }
6631 return FALSE;
6632}
6633
6634#ifdef SPECIAL_WILDCHAR
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006635/*
Bram Moolenaar187a4f22017-02-23 17:07:14 +01006636 * Return TRUE if "p" contains a special wildcard character, one that Vim
6637 * cannot expand, requires using a shell.
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006638 */
6639 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006640has_special_wildchar(char_u *p)
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006641{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006642 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006643 {
Bram Moolenaar187a4f22017-02-23 17:07:14 +01006644 /* Allow for escaping. */
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006645 if (*p == '\\' && p[1] != NUL)
6646 ++p;
6647 else if (vim_strchr((char_u *)SPECIAL_WILDCHAR, *p) != NULL)
6648 return TRUE;
6649 }
6650 return FALSE;
6651}
6652#endif
6653
Bram Moolenaar071d4272004-06-13 20:20:40 +00006654/*
6655 * Generic wildcard expansion code.
6656 *
6657 * Characters in "pat" that should not be expanded must be preceded with a
6658 * backslash. E.g., "/path\ with\ spaces/my\*star*"
6659 *
6660 * Return FAIL when no single file was found. In this case "num_file" is not
6661 * set, and "file" may contain an error message.
6662 * Return OK when some files found. "num_file" is set to the number of
6663 * matches, "file" to the array of matches. Call FreeWild() later.
6664 */
6665 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006666gen_expand_wildcards(
6667 int num_pat, /* number of input patterns */
6668 char_u **pat, /* array of input patterns */
6669 int *num_file, /* resulting number of files */
6670 char_u ***file, /* array of resulting files */
6671 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006672{
6673 int i;
6674 garray_T ga;
6675 char_u *p;
6676 static int recursive = FALSE;
6677 int add_pat;
Bram Moolenaar3f188932015-08-25 13:57:04 +02006678 int retval = OK;
Bram Moolenaard732f9a2010-08-15 13:29:11 +02006679#if defined(FEAT_SEARCHPATH)
6680 int did_expand_in_path = FALSE;
6681#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006682
6683 /*
6684 * expand_env() is called to expand things like "~user". If this fails,
6685 * it calls ExpandOne(), which brings us back here. In this case, always
6686 * call the machine specific expansion function, if possible. Otherwise,
6687 * return FAIL.
6688 */
6689 if (recursive)
6690#ifdef SPECIAL_WILDCHAR
6691 return mch_expand_wildcards(num_pat, pat, num_file, file, flags);
6692#else
6693 return FAIL;
6694#endif
6695
6696#ifdef SPECIAL_WILDCHAR
6697 /*
6698 * If there are any special wildcard characters which we cannot handle
6699 * here, call machine specific function for all the expansion. This
6700 * avoids starting the shell for each argument separately.
6701 * For `=expr` do use the internal function.
6702 */
6703 for (i = 0; i < num_pat; i++)
6704 {
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006705 if (has_special_wildchar(pat[i])
Bram Moolenaar071d4272004-06-13 20:20:40 +00006706# ifdef VIM_BACKTICK
6707 && !(vim_backtick(pat[i]) && pat[i][1] == '=')
6708# endif
6709 )
6710 return mch_expand_wildcards(num_pat, pat, num_file, file, flags);
6711 }
6712#endif
6713
6714 recursive = TRUE;
6715
6716 /*
6717 * The matching file names are stored in a growarray. Init it empty.
6718 */
6719 ga_init2(&ga, (int)sizeof(char_u *), 30);
6720
6721 for (i = 0; i < num_pat; ++i)
6722 {
6723 add_pat = -1;
6724 p = pat[i];
6725
6726#ifdef VIM_BACKTICK
6727 if (vim_backtick(p))
Bram Moolenaar3f188932015-08-25 13:57:04 +02006728 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006729 add_pat = expand_backtick(&ga, p, flags);
Bram Moolenaar3f188932015-08-25 13:57:04 +02006730 if (add_pat == -1)
6731 retval = FAIL;
6732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006733 else
6734#endif
6735 {
6736 /*
6737 * First expand environment variables, "~/" and "~user/".
6738 */
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006739 if (has_env_var(p) || *p == '~')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006740 {
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00006741 p = expand_env_save_opt(p, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006742 if (p == NULL)
6743 p = pat[i];
6744#ifdef UNIX
6745 /*
6746 * On Unix, if expand_env() can't expand an environment
6747 * variable, use the shell to do that. Discard previously
6748 * found file names and start all over again.
6749 */
Bram Moolenaarf4e11432013-07-03 16:53:03 +02006750 else if (has_env_var(p) || *p == '~')
Bram Moolenaar071d4272004-06-13 20:20:40 +00006751 {
6752 vim_free(p);
Bram Moolenaar782027e2009-06-24 14:25:49 +00006753 ga_clear_strings(&ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006754 i = mch_expand_wildcards(num_pat, pat, num_file, file,
Bram Moolenaare4df1642014-08-29 12:58:44 +02006755 flags|EW_KEEPDOLLAR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006756 recursive = FALSE;
6757 return i;
6758 }
6759#endif
6760 }
6761
6762 /*
6763 * If there are wildcards: Expand file names and add each match to
6764 * the list. If there is no match, and EW_NOTFOUND is given, add
6765 * the pattern.
6766 * If there are no wildcards: Add the file name if it exists or
6767 * when EW_NOTFOUND is given.
6768 */
6769 if (mch_has_exp_wildcard(p))
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006770 {
6771#if defined(FEAT_SEARCHPATH)
Bram Moolenaard732f9a2010-08-15 13:29:11 +02006772 if ((flags & EW_PATH)
6773 && !mch_isFullName(p)
6774 && !(p[0] == '.'
6775 && (vim_ispathsep(p[1])
6776 || (p[1] == '.' && vim_ispathsep(p[2]))))
6777 )
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006778 {
Bram Moolenaard732f9a2010-08-15 13:29:11 +02006779 /* :find completion where 'path' is used.
6780 * Recursiveness is OK here. */
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006781 recursive = FALSE;
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006782 add_pat = expand_in_path(&ga, p, flags);
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006783 recursive = TRUE;
Bram Moolenaard732f9a2010-08-15 13:29:11 +02006784 did_expand_in_path = TRUE;
Bram Moolenaar80a7dcf2010-08-04 17:07:20 +02006785 }
Bram Moolenaarcc448b32010-07-14 16:52:17 +02006786 else
6787#endif
6788 add_pat = mch_expandpath(&ga, p, flags);
6789 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006790 }
6791
6792 if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND)))
6793 {
6794 char_u *t = backslash_halve_save(p);
6795
Bram Moolenaar071d4272004-06-13 20:20:40 +00006796 /* When EW_NOTFOUND is used, always add files and dirs. Makes
6797 * "vim c:/" work. */
6798 if (flags & EW_NOTFOUND)
6799 addfile(&ga, t, flags | EW_DIR | EW_FILE);
Bram Moolenaar00efded2016-07-07 14:29:10 +02006800 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006801 addfile(&ga, t, flags);
6802 vim_free(t);
6803 }
6804
Bram Moolenaarb28ebbc2010-07-14 16:59:57 +02006805#if defined(FEAT_SEARCHPATH)
Bram Moolenaard732f9a2010-08-15 13:29:11 +02006806 if (did_expand_in_path && ga.ga_len > 0 && (flags & EW_PATH))
Bram Moolenaarb28ebbc2010-07-14 16:59:57 +02006807 uniquefy_paths(&ga, p);
6808#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006809 if (p != pat[i])
6810 vim_free(p);
6811 }
6812
6813 *num_file = ga.ga_len;
6814 *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data : (char_u **)"";
6815
6816 recursive = FALSE;
6817
Bram Moolenaar336bd622016-01-17 18:23:58 +01006818 return ((flags & EW_EMPTYOK) || ga.ga_data != NULL) ? retval : FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006819}
6820
6821# ifdef VIM_BACKTICK
6822
6823/*
6824 * Return TRUE if we can expand this backtick thing here.
6825 */
6826 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006827vim_backtick(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006828{
6829 return (*p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`');
6830}
6831
6832/*
6833 * Expand an item in `backticks` by executing it as a command.
6834 * Currently only works when pat[] starts and ends with a `.
Bram Moolenaar3f188932015-08-25 13:57:04 +02006835 * Returns number of file names found, -1 if an error is encountered.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006836 */
6837 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006838expand_backtick(
6839 garray_T *gap,
6840 char_u *pat,
6841 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006842{
6843 char_u *p;
6844 char_u *cmd;
6845 char_u *buffer;
6846 int cnt = 0;
6847 int i;
6848
6849 /* Create the command: lop off the backticks. */
6850 cmd = vim_strnsave(pat + 1, (int)STRLEN(pat) - 2);
6851 if (cmd == NULL)
Bram Moolenaar3f188932015-08-25 13:57:04 +02006852 return -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006853
6854#ifdef FEAT_EVAL
6855 if (*cmd == '=') /* `={expr}`: Expand expression */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00006856 buffer = eval_to_string(cmd + 1, &p, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006857 else
6858#endif
Bram Moolenaarc0197e22004-09-13 20:26:32 +00006859 buffer = get_cmd_output(cmd, NULL,
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02006860 (flags & EW_SILENT) ? SHELL_SILENT : 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006861 vim_free(cmd);
6862 if (buffer == NULL)
Bram Moolenaar3f188932015-08-25 13:57:04 +02006863 return -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006864
6865 cmd = buffer;
6866 while (*cmd != NUL)
6867 {
6868 cmd = skipwhite(cmd); /* skip over white space */
6869 p = cmd;
6870 while (*p != NUL && *p != '\r' && *p != '\n') /* skip over entry */
6871 ++p;
6872 /* add an entry if it is not empty */
6873 if (p > cmd)
6874 {
6875 i = *p;
6876 *p = NUL;
6877 addfile(gap, cmd, flags);
6878 *p = i;
6879 ++cnt;
6880 }
6881 cmd = p;
6882 while (*cmd != NUL && (*cmd == '\r' || *cmd == '\n'))
6883 ++cmd;
6884 }
6885
6886 vim_free(buffer);
6887 return cnt;
6888}
6889# endif /* VIM_BACKTICK */
6890
6891/*
6892 * Add a file to a file list. Accepted flags:
6893 * EW_DIR add directories
6894 * EW_FILE add files
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00006895 * EW_EXEC add executable files
Bram Moolenaar071d4272004-06-13 20:20:40 +00006896 * EW_NOTFOUND add even when it doesn't exist
6897 * EW_ADDSLASH add slash after directory name
Bram Moolenaard8b77f72015-03-05 21:21:19 +01006898 * EW_ALLLINKS add symlink also when the referred file does not exist
Bram Moolenaar071d4272004-06-13 20:20:40 +00006899 */
6900 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006901addfile(
6902 garray_T *gap,
6903 char_u *f, /* filename */
6904 int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006905{
6906 char_u *p;
6907 int isdir;
Bram Moolenaar8767f522016-07-01 17:17:39 +02006908 stat_T sb;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006909
Bram Moolenaard8b77f72015-03-05 21:21:19 +01006910 /* if the file/dir/link doesn't exist, may not add it */
6911 if (!(flags & EW_NOTFOUND) && ((flags & EW_ALLLINKS)
Bram Moolenaarab11a592015-03-06 22:00:11 +01006912 ? mch_lstat((char *)f, &sb) < 0 : mch_getperm(f) < 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006913 return;
6914
6915#ifdef FNAME_ILLEGAL
6916 /* if the file/dir contains illegal characters, don't add it */
6917 if (vim_strpbrk(f, (char_u *)FNAME_ILLEGAL) != NULL)
6918 return;
6919#endif
6920
6921 isdir = mch_isdir(f);
6922 if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE)))
6923 return;
6924
Bram Moolenaarb5971142015-03-21 17:32:19 +01006925 /* If the file isn't executable, may not add it. Do accept directories.
6926 * When invoked from expand_shellcmd() do not use $PATH. */
6927 if (!isdir && (flags & EW_EXEC)
6928 && !mch_can_exe(f, NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00006929 return;
6930
Bram Moolenaar071d4272004-06-13 20:20:40 +00006931 /* Make room for another item in the file list. */
6932 if (ga_grow(gap, 1) == FAIL)
6933 return;
6934
6935 p = alloc((unsigned)(STRLEN(f) + 1 + isdir));
6936 if (p == NULL)
6937 return;
6938
6939 STRCPY(p, f);
6940#ifdef BACKSLASH_IN_FILENAME
6941 slash_adjust(p);
6942#endif
6943 /*
6944 * Append a slash or backslash after directory names if none is present.
6945 */
6946#ifndef DONT_ADD_PATHSEP_TO_DIR
6947 if (isdir && (flags & EW_ADDSLASH))
6948 add_pathsep(p);
6949#endif
6950 ((char_u **)gap->ga_data)[gap->ga_len++] = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006951}
6952#endif /* !NO_EXPANDPATH */
6953
6954#if defined(VIM_BACKTICK) || defined(FEAT_EVAL) || defined(PROTO)
6955
6956#ifndef SEEK_SET
6957# define SEEK_SET 0
6958#endif
6959#ifndef SEEK_END
6960# define SEEK_END 2
6961#endif
6962
6963/*
6964 * Get the stdout of an external command.
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02006965 * If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not
6966 * NULL store the length there.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006967 * Returns an allocated string, or NULL for error.
6968 */
6969 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01006970get_cmd_output(
6971 char_u *cmd,
6972 char_u *infile, /* optional input file name */
6973 int flags, /* can be SHELL_SILENT */
6974 int *ret_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006975{
6976 char_u *tempname;
6977 char_u *command;
6978 char_u *buffer = NULL;
6979 int len;
6980 int i = 0;
6981 FILE *fd;
6982
6983 if (check_restricted() || check_secure())
6984 return NULL;
6985
6986 /* get a name for the temp file */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006987 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006988 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006989 emsg(_(e_notmp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006990 return NULL;
6991 }
6992
6993 /* Add the redirection stuff */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00006994 command = make_filter_cmd(cmd, infile, tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006995 if (command == NULL)
6996 goto done;
6997
6998 /*
6999 * Call the shell to execute the command (errors are ignored).
7000 * Don't check timestamps here.
7001 */
7002 ++no_check_timestamps;
7003 call_shell(command, SHELL_DOOUT | SHELL_EXPAND | flags);
7004 --no_check_timestamps;
7005
7006 vim_free(command);
7007
7008 /*
7009 * read the names from the file into memory
7010 */
7011# ifdef VMS
Bram Moolenaar25394022007-05-10 19:06:20 +00007012 /* created temporary file is not always readable as binary */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007013 fd = mch_fopen((char *)tempname, "r");
7014# else
7015 fd = mch_fopen((char *)tempname, READBIN);
7016# endif
7017
7018 if (fd == NULL)
7019 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007020 semsg(_(e_notopen), tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007021 goto done;
7022 }
7023
7024 fseek(fd, 0L, SEEK_END);
7025 len = ftell(fd); /* get size of temp file */
7026 fseek(fd, 0L, SEEK_SET);
7027
7028 buffer = alloc(len + 1);
7029 if (buffer != NULL)
7030 i = (int)fread((char *)buffer, (size_t)1, (size_t)len, fd);
7031 fclose(fd);
7032 mch_remove(tempname);
7033 if (buffer == NULL)
7034 goto done;
7035#ifdef VMS
7036 len = i; /* VMS doesn't give us what we asked for... */
7037#endif
7038 if (i != len)
7039 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007040 semsg(_(e_notread), tempname);
Bram Moolenaard23a8232018-02-10 18:45:26 +01007041 VIM_CLEAR(buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007042 }
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02007043 else if (ret_len == NULL)
Bram Moolenaarfb332a22013-08-03 14:10:50 +02007044 {
7045 /* Change NUL into SOH, otherwise the string is truncated. */
7046 for (i = 0; i < len; ++i)
Bram Moolenaarf40f4ab2013-08-03 17:31:28 +02007047 if (buffer[i] == NUL)
7048 buffer[i] = 1;
Bram Moolenaarfb332a22013-08-03 14:10:50 +02007049
Bram Moolenaar162bd912010-07-28 22:29:10 +02007050 buffer[len] = NUL; /* make sure the buffer is terminated */
Bram Moolenaarfb332a22013-08-03 14:10:50 +02007051 }
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02007052 else
7053 *ret_len = len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007054
7055done:
7056 vim_free(tempname);
7057 return buffer;
7058}
7059#endif
7060
7061/*
7062 * Free the list of files returned by expand_wildcards() or other expansion
7063 * functions.
7064 */
7065 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01007066FreeWild(int count, char_u **files)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007067{
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00007068 if (count <= 0 || files == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007070 while (count--)
7071 vim_free(files[count]);
7072 vim_free(files);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007073}
7074
7075/*
Bram Moolenaara9dc3752010-07-11 20:46:53 +02007076 * Return TRUE when need to go to Insert mode because of 'insertmode'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007077 * Don't do this when still processing a command or a mapping.
7078 * Don't do this when inside a ":normal" command.
7079 */
7080 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01007081goto_im(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007082{
7083 return (p_im && stuff_empty() && typebuf_typed());
7084}
Bram Moolenaar75a8d742014-05-07 15:10:21 +02007085
7086/*
Bram Moolenaar050fe7e2014-05-22 14:00:16 +02007087 * Returns the isolated name of the shell in allocated memory:
Bram Moolenaar75a8d742014-05-07 15:10:21 +02007088 * - Skip beyond any path. E.g., "/usr/bin/csh -f" -> "csh -f".
7089 * - Remove any argument. E.g., "csh -f" -> "csh".
7090 * But don't allow a space in the path, so that this works:
7091 * "/usr/bin/csh --rcfile ~/.cshrc"
7092 * But don't do that for Windows, it's common to have a space in the path.
7093 */
7094 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01007095get_isolated_shell_name(void)
Bram Moolenaar75a8d742014-05-07 15:10:21 +02007096{
7097 char_u *p;
7098
7099#ifdef WIN3264
7100 p = gettail(p_sh);
7101 p = vim_strnsave(p, (int)(skiptowhite(p) - p));
7102#else
7103 p = skiptowhite(p_sh);
7104 if (*p == NUL)
7105 {
7106 /* No white space, use the tail. */
7107 p = vim_strsave(gettail(p_sh));
7108 }
7109 else
7110 {
7111 char_u *p1, *p2;
7112
7113 /* Find the last path separator before the space. */
7114 p1 = p_sh;
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007115 for (p2 = p_sh; p2 < p; MB_PTR_ADV(p2))
Bram Moolenaar75a8d742014-05-07 15:10:21 +02007116 if (vim_ispathsep(*p2))
7117 p1 = p2 + 1;
7118 p = vim_strnsave(p1, (int)(p - p1));
7119 }
7120#endif
7121 return p;
7122}