blob: a8be96dc32b0a57f90efa709c3e81f97ced06084 [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 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
19#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar975b5272016-03-15 23:10:59 +010020# if defined(FEAT_TIMERS) || defined(PROTO)
21static timer_T *first_timer = NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +020022static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +010023
Bram Moolenaar2f106582019-05-08 21:59:25 +020024/*
25 * Return time left until "due". Negative if past "due".
26 */
Bram Moolenaar56bc8e22018-05-10 18:05:56 +020027 long
Bram Moolenaar51b0f372017-11-18 18:52:04 +010028proftime_time_left(proftime_T *due, proftime_T *now)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020029{
Bram Moolenaar4f974752019-02-17 17:44:42 +010030# ifdef MSWIN
Bram Moolenaara8e93d62017-09-18 21:50:47 +020031 LARGE_INTEGER fr;
32
Bram Moolenaar51b0f372017-11-18 18:52:04 +010033 if (now->QuadPart > due->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020034 return 0;
35 QueryPerformanceFrequency(&fr);
Bram Moolenaar51b0f372017-11-18 18:52:04 +010036 return (long)(((double)(due->QuadPart - now->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020037 / (double)fr.QuadPart) * 1000);
38# else
Bram Moolenaar51b0f372017-11-18 18:52:04 +010039 if (now->tv_sec > due->tv_sec)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020040 return 0;
Bram Moolenaar51b0f372017-11-18 18:52:04 +010041 return (due->tv_sec - now->tv_sec) * 1000
42 + (due->tv_usec - now->tv_usec) / 1000;
Bram Moolenaara8e93d62017-09-18 21:50:47 +020043# endif
44}
Bram Moolenaar417ccd72016-09-01 21:26:20 +020045
Bram Moolenaar975b5272016-03-15 23:10:59 +010046/*
47 * Insert a timer in the list of timers.
48 */
49 static void
50insert_timer(timer_T *timer)
51{
52 timer->tr_next = first_timer;
53 timer->tr_prev = NULL;
54 if (first_timer != NULL)
55 first_timer->tr_prev = timer;
56 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +020057 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +010058}
59
60/*
61 * Take a timer out of the list of timers.
62 */
63 static void
64remove_timer(timer_T *timer)
65{
66 if (timer->tr_prev == NULL)
67 first_timer = timer->tr_next;
68 else
69 timer->tr_prev->tr_next = timer->tr_next;
70 if (timer->tr_next != NULL)
71 timer->tr_next->tr_prev = timer->tr_prev;
72}
73
74 static void
75free_timer(timer_T *timer)
76{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020077 free_callback(&timer->tr_callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020078 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +010079}
80
81/*
82 * Create a timer and return it. NULL if out of memory.
83 * Caller should set the callback.
84 */
85 timer_T *
86create_timer(long msec, int repeat)
87{
Bram Moolenaarc799fe22019-05-28 23:08:19 +020088 timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
Bram Moolenaaree39ef02016-09-10 19:17:42 +020089 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +010090
91 if (timer == NULL)
92 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +020093 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +020094 /* Overflow! Might cause duplicates... */
95 last_timer_id = 0;
96 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +010097 insert_timer(timer);
98 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +010099 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200100 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100101
102 profile_setlimit(msec, &timer->tr_due);
103 return timer;
104}
105
106/*
107 * Invoke the callback of "timer".
108 */
109 static void
110timer_callback(timer_T *timer)
111{
112 typval_T rettv;
113 int dummy;
114 typval_T argv[2];
115
116 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200117 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100118 argv[1].v_type = VAR_UNKNOWN;
119
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200120 call_callback(&timer->tr_callback, -1,
121 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100122 clear_tv(&rettv);
123}
124
125/*
126 * Call timers that are due.
127 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200128 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100129 */
130 long
Bram Moolenaarcf089462016-06-12 21:18:43 +0200131check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100132{
133 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200134 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100135 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +0100136 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100137 proftime_T now;
138 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200139 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200140 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100141
Bram Moolenaarc577d812017-07-08 22:37:34 +0200142 /* Don't run any timers while exiting or dealing with an error. */
143 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200144 return next_due;
145
Bram Moolenaar75537a92016-09-05 22:45:28 +0200146 profile_start(&now);
147 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100148 {
Bram Moolenaar75537a92016-09-05 22:45:28 +0200149 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200150
Bram Moolenaar75537a92016-09-05 22:45:28 +0200151 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
152 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100153 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200154 if (this_due <= 1)
155 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200156 /* Save and restore a lot of flags, because the timer fires while
157 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200158 int save_timer_busy = timer_busy;
159 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200160 int save_did_emsg = did_emsg;
161 int save_called_emsg = called_emsg;
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200162 int save_must_redraw = must_redraw;
163 int save_trylevel = trylevel;
Bram Moolenaare723c422017-09-06 23:40:10 +0200164 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200165 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare96a2492019-06-25 04:12:16 +0200166 int save_may_garbage_collect = may_garbage_collect;
Bram Moolenaare723c422017-09-06 23:40:10 +0200167 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200168 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200169
Bram Moolenaare723c422017-09-06 23:40:10 +0200170 /* Create a scope for running the timer callback, ignoring most of
171 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200172 timer_busy = timer_busy > 0 || vgetc_busy > 0;
173 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +0200174 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200175 did_emsg = FALSE;
176 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200177 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +0200178 trylevel = 0;
179 did_throw = FALSE;
180 current_exception = NULL;
Bram Moolenaare96a2492019-06-25 04:12:16 +0200181 may_garbage_collect = FALSE;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200182 save_vimvars(&vvsave);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200183
Bram Moolenaar75537a92016-09-05 22:45:28 +0200184 timer->tr_firing = TRUE;
185 timer_callback(timer);
186 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200187
Bram Moolenaar75537a92016-09-05 22:45:28 +0200188 timer_next = timer->tr_next;
189 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200190 timer_busy = save_timer_busy;
191 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200192 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200193 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200194 did_emsg = save_did_emsg;
195 called_emsg = save_called_emsg;
196 trylevel = save_trylevel;
197 did_throw = save_did_throw;
198 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200199 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200200 if (must_redraw != 0)
201 need_update_screen = TRUE;
202 must_redraw = must_redraw > save_must_redraw
203 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200204 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200205 may_garbage_collect = save_may_garbage_collect;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200206
207 /* Only fire the timer again if it repeats and stop_timer() wasn't
208 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200209 if (timer->tr_repeat != 0 && timer->tr_id != -1
210 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200211 {
212 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100213 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200214 if (this_due < 1)
215 this_due = 1;
216 if (timer->tr_repeat > 0)
217 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100218 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200219 else
220 {
221 this_due = -1;
222 remove_timer(timer);
223 free_timer(timer);
224 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100225 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200226 if (this_due > 0 && (next_due == -1 || next_due > this_due))
227 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100228 }
229
230 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200231 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100232
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100233#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100234 if (bevalexpr_due_set)
235 {
236 this_due = proftime_time_left(&bevalexpr_due, &now);
237 if (this_due <= 1)
238 {
239 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100240 if (balloonEval == NULL)
241 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200242 balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100243 balloonEvalForTerm = TRUE;
244 }
245 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200246 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100247 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200248 setcursor();
249 out_flush();
250 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100251 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200252 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100253 next_due = this_due;
254 }
255#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200256#ifdef FEAT_TERMINAL
257 /* Some terminal windows may need their buffer updated. */
258 next_due = term_check_timers(next_due, &now);
259#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100260
Bram Moolenaar75537a92016-09-05 22:45:28 +0200261 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100262}
263
264/*
265 * Find a timer by ID. Returns NULL if not found;
266 */
267 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200268find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100269{
270 timer_T *timer;
271
Bram Moolenaar75537a92016-09-05 22:45:28 +0200272 if (id >= 0)
273 {
274 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
275 if (timer->tr_id == id)
276 return timer;
277 }
278 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100279}
280
281
282/*
283 * Stop a timer and delete it.
284 */
285 void
286stop_timer(timer_T *timer)
287{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200288 if (timer->tr_firing)
289 /* Free the timer after the callback returns. */
290 timer->tr_id = -1;
291 else
292 {
293 remove_timer(timer);
294 free_timer(timer);
295 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100296}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200297
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200298 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200299stop_all_timers(void)
300{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200301 timer_T *timer;
302 timer_T *timer_next;
303
304 for (timer = first_timer; timer != NULL; timer = timer_next)
305 {
306 timer_next = timer->tr_next;
307 stop_timer(timer);
308 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200309}
310
311 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200312add_timer_info(typval_T *rettv, timer_T *timer)
313{
314 list_T *list = rettv->vval.v_list;
315 dict_T *dict = dict_alloc();
316 dictitem_T *di;
317 long remaining;
318 proftime_T now;
319
320 if (dict == NULL)
321 return;
322 list_append_dict(list, dict);
323
Bram Moolenaare0be1672018-07-08 16:50:37 +0200324 dict_add_number(dict, "id", timer->tr_id);
325 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200326
327 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100328 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200329 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200330
Bram Moolenaare0be1672018-07-08 16:50:37 +0200331 dict_add_number(dict, "repeat",
332 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
333 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200334
335 di = dictitem_alloc((char_u *)"callback");
336 if (di != NULL)
337 {
338 if (dict_add(dict, di) == FAIL)
339 vim_free(di);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200340 else
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200341 put_callback(&timer->tr_callback, &di->di_tv);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200342 }
343}
344
345 void
346add_timer_info_all(typval_T *rettv)
347{
348 timer_T *timer;
349
350 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200351 if (timer->tr_id != -1)
352 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200353}
354
Bram Moolenaare3188e22016-05-31 21:13:04 +0200355/*
356 * Mark references in partials of timers.
357 */
358 int
359set_ref_in_timer(int copyID)
360{
361 int abort = FALSE;
362 timer_T *timer;
363 typval_T tv;
364
Bram Moolenaar75a1a942019-06-20 03:45:36 +0200365 for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
Bram Moolenaare3188e22016-05-31 21:13:04 +0200366 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200367 if (timer->tr_callback.cb_partial != NULL)
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200368 {
369 tv.v_type = VAR_PARTIAL;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200370 tv.vval.v_partial = timer->tr_callback.cb_partial;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200371 }
372 else
373 {
374 tv.v_type = VAR_FUNC;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200375 tv.vval.v_string = timer->tr_callback.cb_name;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200376 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200377 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
378 }
379 return abort;
380}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200381
382# if defined(EXITFREE) || defined(PROTO)
383 void
384timer_free_all()
385{
386 timer_T *timer;
387
388 while (first_timer != NULL)
389 {
390 timer = first_timer;
391 remove_timer(timer);
392 free_timer(timer);
393 }
394}
395# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100396# endif
397
Bram Moolenaar071d4272004-06-13 20:20:40 +0000398#endif
399
400/*
401 * If 'autowrite' option set, try to write the file.
402 * Careful: autocommands may make "buf" invalid!
403 *
404 * return FAIL for failure, OK otherwise
405 */
406 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100407autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408{
Bram Moolenaar373154b2007-02-13 05:19:30 +0000409 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200410 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +0000411
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412 if (!(p_aw || p_awa) || !p_write
413#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +0000414 /* never autowrite a "nofile" or "nowrite" buffer */
415 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +0000417 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200419 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +0000420 r = buf_write_all(buf, forceit);
421
422 /* Writing may succeed but the buffer still changed, e.g., when there is a
423 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200424 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +0000425 r = FAIL;
426 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427}
428
429/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200430 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 */
432 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100433autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434{
435 buf_T *buf;
436
437 if (!(p_aw || p_awa) || !p_write)
438 return;
Bram Moolenaar29323592016-07-24 22:04:11 +0200439 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200440 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200442 bufref_T bufref;
443
444 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100445
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100447
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200449 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451 }
452}
453
454/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100455 * Return TRUE if buffer was changed and cannot be abandoned.
456 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000457 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100459check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200461 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200462 bufref_T bufref;
463
464 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100465
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 if ( !forceit
467 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100468 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
469 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 {
471#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
472 if ((p_confirm || cmdmod.confirm) && p_write)
473 {
474 buf_T *buf2;
475 int count = 0;
476
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100477 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +0200478 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479 if (bufIsChanged(buf2)
480 && (buf2->b_ffname != NULL
481# ifdef FEAT_BROWSE
482 || cmdmod.browse
483# endif
484 ))
485 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200486 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000487 /* Autocommand deleted buffer, oops! It's not changed now. */
488 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100489
Bram Moolenaar071d4272004-06-13 20:20:40 +0000490 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100491
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200492 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000493 /* Autocommand deleted buffer, oops! It's not changed now. */
494 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495 return bufIsChanged(buf);
496 }
497#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100498 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +0200499 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100500 else
Bram Moolenaar7a760922018-02-19 23:10:02 +0100501 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 return TRUE;
503 }
504 return FALSE;
505}
506
507#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
508
509#if defined(FEAT_BROWSE) || defined(PROTO)
510/*
511 * When wanting to write a file without a file name, ask the user for a name.
512 */
513 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100514browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000515{
516 if (buf->b_fname == NULL)
517 {
518 char_u *fname;
519
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000520 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
521 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 if (fname != NULL)
523 {
524 if (setfname(buf, fname, NULL, TRUE) == OK)
525 buf->b_flags |= BF_NOTEDITED;
526 vim_free(fname);
527 }
528 }
529}
530#endif
531
532/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +0200533 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 * Must check 'write' option first!
535 */
536 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100537dialog_changed(
538 buf_T *buf,
539 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540{
Bram Moolenaard9462e32011-04-11 21:35:11 +0200541 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 int ret;
543 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +0200544 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +0200546 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 if (checkall)
548 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
549 else
550 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
551
Bram Moolenaar4ca41532019-05-09 21:48:37 +0200552 // Init ea pseudo-structure, this is needed for the check_overwrite()
553 // function.
554 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +0200555
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 if (ret == VIM_YES)
557 {
558#ifdef FEAT_BROWSE
559 /* May get file name, when there is none */
560 browse_save_fname(buf);
561#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200562 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
563 buf->b_fname, buf->b_ffname, FALSE) == OK)
564 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 (void)buf_write_all(buf, FALSE);
566 }
567 else if (ret == VIM_NO)
568 {
Bram Moolenaarc024b462019-06-08 18:07:21 +0200569 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 }
571 else if (ret == VIM_ALL)
572 {
573 /*
574 * Write all modified files that can be written.
575 * Skip readonly buffers, these need to be confirmed
576 * individually.
577 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200578 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 {
580 if (bufIsChanged(buf2)
581 && (buf2->b_ffname != NULL
582#ifdef FEAT_BROWSE
583 || cmdmod.browse
584#endif
585 )
586 && !buf2->b_p_ro)
587 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200588 bufref_T bufref;
589
590 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591#ifdef FEAT_BROWSE
592 /* May get file name, when there is none */
593 browse_save_fname(buf2);
594#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200595 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
596 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
597 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000598 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100599
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200601 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 }
604 }
605 }
606 else if (ret == VIM_DISCARDALL)
607 {
608 /*
609 * mark all buffers as unchanged
610 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200611 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +0200612 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613 }
614}
615#endif
616
617/*
618 * Return TRUE if the buffer "buf" can be abandoned, either by making it
619 * hidden, autowriting it or unloading it.
620 */
621 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100622can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623{
Bram Moolenaareb44a682017-08-03 22:44:55 +0200624 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 || !bufIsChanged(buf)
626 || buf->b_nwindows > 1
627 || autowrite(buf, forceit) == OK
628 || forceit);
629}
630
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100631/*
632 * Add a buffer number to "bufnrs", unless it's already there.
633 */
634 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100635add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100636{
637 int i;
638
639 for (i = 0; i < *bufnump; ++i)
640 if (bufnrs[i] == nr)
641 return;
642 bufnrs[*bufnump] = nr;
643 *bufnump = *bufnump + 1;
644}
645
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646/*
647 * Return TRUE if any buffer was changed and cannot be abandoned.
648 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100649 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +0100650 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 */
652 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100653check_changed_any(
654 int hidden, /* Only check hidden buffers */
655 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100657 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658 buf_T *buf;
659 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100660 int i;
661 int bufnum = 0;
662 int bufcount = 0;
663 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100664 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100667 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +0200668 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100669 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100671 if (bufcount == 0)
672 return FALSE;
673
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200674 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100675 if (bufnrs == NULL)
676 return FALSE;
677
678 /* curbuf */
679 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100680
681 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100682 FOR_ALL_WINDOWS(wp)
683 if (wp->w_buffer != curbuf)
684 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
685
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100686 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +0200687 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100688 if (tp != curtab)
689 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
690 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100691
692 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +0200693 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100694 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
695
696 for (i = 0; i < bufnum; ++i)
697 {
698 buf = buflist_findnr(bufnrs[i]);
699 if (buf == NULL)
700 continue;
701 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
702 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200703 bufref_T bufref;
704
705 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100706#ifdef FEAT_TERMINAL
707 if (term_job_running(buf->b_term))
708 {
709 if (term_try_stop_job(buf) == FAIL)
710 break;
711 }
712 else
713#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100714 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +0200715 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100716 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
717 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200718 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100719 break; /* didn't save - still changes */
720 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 }
722
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100723 if (i >= bufnum)
724 goto theend;
725
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100726 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100727 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000728 exiting = FALSE;
729#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
730 /*
731 * When ":confirm" used, don't give an error message.
732 */
733 if (!(p_confirm || cmdmod.confirm))
734#endif
735 {
736 /* There must be a wait_return for this message, do_buffer()
737 * may cause a redraw. But wait_return() is a no-op when vgetc()
738 * is busy (Quit used from window menu), then make sure we don't
739 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +0000740 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741 {
742 msg_row = cmdline_row;
743 msg_col = 0;
744 msg_didout = FALSE;
745 }
Bram Moolenaareb44a682017-08-03 22:44:55 +0200746 if (
747#ifdef FEAT_TERMINAL
748 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100749 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +0200750 buf->b_fname)
751 :
752#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100753 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200754 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 {
756 save = no_wait_return;
757 no_wait_return = FALSE;
758 wait_return(FALSE);
759 no_wait_return = save;
760 }
761 }
762
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 /* Try to find a window that contains the buffer. */
764 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100765 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 if (wp->w_buffer == buf)
767 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200768 bufref_T bufref;
769
770 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100771
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100772 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100773
Bram Moolenaarbdace832019-03-02 10:13:42 +0100774 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200775 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100776 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100777 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100779buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780
781 /* Open the changed buffer in the current window. */
782 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +0100783 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100785theend:
786 vim_free(bufnrs);
787 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000788}
789
790/*
791 * return FAIL if there is no file name, OK if there is one
792 * give error message for FAIL
793 */
794 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100795check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796{
797 if (curbuf->b_ffname == NULL)
798 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100799 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800 return FAIL;
801 }
802 return OK;
803}
804
805/*
806 * flush the contents of a buffer, unless it has no file name
807 *
808 * return FAIL for failure, OK otherwise
809 */
810 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100811buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812{
813 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815
816 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
817 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
818 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000820 {
Bram Moolenaar8820b482017-03-16 17:23:31 +0100821 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +0100822 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000823 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 return retval;
825}
826
827/*
828 * Code to handle the argument list.
829 */
830
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200831static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100832static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200833static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000834#define AL_SET 1
835#define AL_ADD 2
836#define AL_DEL 3
837
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000839 * Isolate one argument, taking backticks.
840 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 * Return a pointer to the start of the next argument.
842 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000843 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100844do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845{
846 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 int inbacktick;
848
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 inbacktick = FALSE;
850 for (p = str; *str; ++str)
851 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000852 /* When the backslash is used for escaping the special meaning of a
853 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 if (rem_backslash(str))
855 {
856 *p++ = *str++;
857 *p++ = *str;
858 }
859 else
860 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000861 /* An item ends at a space not in backticks */
862 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000864 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000866 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 }
868 }
869 str = skipwhite(str);
870 *p = NUL;
871
872 return str;
873}
874
Bram Moolenaar86b68352004-12-27 21:59:20 +0000875/*
876 * Separate the arguments in "str" and return a list of pointers in the
877 * growarray "gap".
878 */
Bram Moolenaar398ee732017-08-03 14:29:14 +0200879 static int
880get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +0000881{
882 ga_init2(gap, (int)sizeof(char_u *), 20);
883 while (*str != NUL)
884 {
885 if (ga_grow(gap, 1) == FAIL)
886 {
887 ga_clear(gap);
888 return FAIL;
889 }
890 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
891
Bram Moolenaar398ee732017-08-03 14:29:14 +0200892 /* If str is escaped, don't handle backslashes or spaces */
893 if (!escaped)
894 return OK;
895
Bram Moolenaar86b68352004-12-27 21:59:20 +0000896 /* Isolate one argument, change it in-place, put a NUL after it. */
897 str = do_one_arg(str);
898 }
899 return OK;
900}
901
Bram Moolenaar7df351e2006-01-23 22:30:28 +0000902#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000903/*
904 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +0200905 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000906 * Return FAIL or OK.
907 */
908 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100909get_arglist_exp(
910 char_u *str,
911 int *fcountp,
912 char_u ***fnamesp,
913 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000914{
915 garray_T ga;
916 int i;
917
Bram Moolenaar398ee732017-08-03 14:29:14 +0200918 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000919 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +0200920 if (wig == TRUE)
921 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
922 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
923 else
924 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
925 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
926
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000927 ga_clear(&ga);
928 return i;
929}
930#endif
931
Bram Moolenaar071d4272004-06-13 20:20:40 +0000932/*
933 * Redefine the argument list.
934 */
935 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100936set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937{
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200938 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000939}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000940
941/*
942 * "what" == AL_SET: Redefine the argument list to 'str'.
943 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
944 * "what" == AL_DEL: remove files in 'str' from the argument list.
945 *
946 * Return FAIL for failure, OK otherwise.
947 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000948 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100949do_arglist(
950 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +0100951 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200952 int after UNUSED, // 0 means before first one
953 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954{
955 garray_T new_ga;
956 int exp_count;
957 char_u **exp_files;
958 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000959 char_u *p;
960 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +0200961 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000962
963 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +0100964 * Set default argument for ":argadd" command.
965 */
966 if (what == AL_ADD && *str == NUL)
967 {
968 if (curbuf->b_ffname == NULL)
969 return FAIL;
970 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +0200971 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +0100972 }
973
974 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975 * Collect all file name arguments in "new_ga".
976 */
Bram Moolenaar398ee732017-08-03 14:29:14 +0200977 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +0000978 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980 if (what == AL_DEL)
981 {
982 regmatch_T regmatch;
983 int didone;
984
985 /*
986 * Delete the items: use each item as a regexp and find a match in the
987 * argument list.
988 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +0100989 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
991 {
992 p = ((char_u **)new_ga.ga_data)[i];
993 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
994 if (p == NULL)
995 break;
996 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
997 if (regmatch.regprog == NULL)
998 {
999 vim_free(p);
1000 break;
1001 }
1002
1003 didone = FALSE;
1004 for (match = 0; match < ARGCOUNT; ++match)
1005 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1006 (colnr_T)0))
1007 {
1008 didone = TRUE;
1009 vim_free(ARGLIST[match].ae_fname);
1010 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1011 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1012 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001013 if (curwin->w_arg_idx > match)
1014 --curwin->w_arg_idx;
1015 --match;
1016 }
1017
Bram Moolenaar473de612013-06-08 18:19:48 +02001018 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019 vim_free(p);
1020 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001021 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022 }
1023 ga_clear(&new_ga);
1024 }
1025 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026 {
1027 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1028 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1029 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01001030 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001032 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 return FAIL;
1034 }
1035
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 if (what == AL_ADD)
1037 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001038 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 vim_free(exp_files);
1040 }
1041 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001042 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 }
1044
1045 alist_check_arg_idx();
1046
1047 return OK;
1048}
1049
1050/*
1051 * Check the validity of the arg_idx for each other window.
1052 */
1053 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001054alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001057 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058
Bram Moolenaarf740b292006-02-16 22:11:02 +00001059 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060 if (win->w_alist == curwin->w_alist)
1061 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062}
1063
1064/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001065 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001066 * index.
1067 */
1068 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001069editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001070{
1071 return !(win->w_arg_idx >= WARGCOUNT(win)
1072 || (win->w_buffer->b_fnum
1073 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1074 && (win->w_buffer->b_ffname == NULL
1075 || !(fullpathcmp(
1076 alist_name(&WARGLIST(win)[win->w_arg_idx]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001077 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))));
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001078}
1079
1080/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 * Check if window "win" is editing the w_arg_idx file in its argument list.
1082 */
1083 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001084check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001086 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 {
1088 /* We are not editing the current entry in the argument list.
1089 * Set "arg_had_last" if we are editing the last one. */
1090 win->w_arg_idx_invalid = TRUE;
1091 if (win->w_arg_idx != WARGCOUNT(win) - 1
1092 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001094 && GARGCOUNT > 0
1095 && win->w_arg_idx < GARGCOUNT
1096 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1097 || (win->w_buffer->b_ffname != NULL
1098 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001099 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100 arg_had_last = TRUE;
1101 }
1102 else
1103 {
1104 /* We are editing the current entry in the argument list.
1105 * Set "arg_had_last" if it's also the last one */
1106 win->w_arg_idx_invalid = FALSE;
1107 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02001108 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109 arg_had_last = TRUE;
1110 }
1111}
1112
1113/*
1114 * ":args", ":argslocal" and ":argsglobal".
1115 */
1116 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001117ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118{
1119 int i;
1120
1121 if (eap->cmdidx != CMD_args)
1122 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123 alist_unlink(ALIST(curwin));
1124 if (eap->cmdidx == CMD_argglobal)
1125 ALIST(curwin) = &global_alist;
1126 else /* eap->cmdidx == CMD_arglocal */
1127 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 }
1129
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01001130 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 {
1132 /*
1133 * ":args file ..": define new argument list, handle like ":next"
1134 * Also for ":argslocal file .." and ":argsglobal file ..".
1135 */
1136 ex_next(eap);
1137 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001138 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001139 {
1140 /*
1141 * ":args": list arguments.
1142 */
1143 if (ARGCOUNT > 0)
1144 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001145 char_u **items = ALLOC_MULT(char_u *, ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001146
1147 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001148 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001149 /* Overwrite the command, for a short list there is no
1150 * scrolling required and no wait_return(). */
1151 gotocmdline(TRUE);
1152
1153 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001154 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001155 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
1156 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 }
1158 }
1159 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 else if (eap->cmdidx == CMD_arglocal)
1161 {
1162 garray_T *gap = &curwin->w_alist->al_ga;
1163
1164 /*
1165 * ":argslocal": make a local copy of the global argument list.
1166 */
1167 if (ga_grow(gap, GARGCOUNT) == OK)
1168 for (i = 0; i < GARGCOUNT; ++i)
1169 if (GARGLIST[i].ae_fname != NULL)
1170 {
1171 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1172 vim_strsave(GARGLIST[i].ae_fname);
1173 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1174 GARGLIST[i].ae_fnum;
1175 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176 }
1177 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178}
1179
1180/*
1181 * ":previous", ":sprevious", ":Next" and ":sNext".
1182 */
1183 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001184ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185{
1186 /* If past the last one already, go to the last one. */
1187 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1188 do_argfile(eap, ARGCOUNT - 1);
1189 else
1190 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1191}
1192
1193/*
1194 * ":rewind", ":first", ":sfirst" and ":srewind".
1195 */
1196 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001197ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198{
1199 do_argfile(eap, 0);
1200}
1201
1202/*
1203 * ":last" and ":slast".
1204 */
1205 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001206ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207{
1208 do_argfile(eap, ARGCOUNT - 1);
1209}
1210
1211/*
1212 * ":argument" and ":sargument".
1213 */
1214 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001215ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216{
1217 int i;
1218
1219 if (eap->addr_count > 0)
1220 i = eap->line2 - 1;
1221 else
1222 i = curwin->w_arg_idx;
1223 do_argfile(eap, i);
1224}
1225
1226/*
1227 * Edit file "argn" of the argument lists.
1228 */
1229 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001230do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231{
1232 int other;
1233 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001234 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235
Bram Moolenaar8cdbd5b2019-06-16 15:50:45 +02001236 if (ERROR_IF_POPUP_WINDOW)
Bram Moolenaar815b76b2019-06-01 14:15:52 +02001237 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 if (argn < 0 || argn >= ARGCOUNT)
1239 {
1240 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001241 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001243 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001245 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246 }
1247 else
1248 {
1249 setpcmark();
1250#ifdef FEAT_GUI
1251 need_mouse_correct = TRUE;
1252#endif
1253
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00001254 /* split window or create new tab page first */
1255 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 {
1257 if (win_split(0, 0) == FAIL)
1258 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001259 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 }
1261 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 {
1263 /*
1264 * if 'hidden' set, only check for changed file when re-editing
1265 * the same buffer
1266 */
1267 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02001268 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 {
1270 p = fix_fname(alist_name(&ARGLIST[argn]));
1271 other = otherfile(p);
1272 vim_free(p);
1273 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001274 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001275 && check_changed(curbuf, CCGD_AW
1276 | (other ? 0 : CCGD_MULTWIN)
1277 | (eap->forceit ? CCGD_FORCEIT : 0)
1278 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001279 return;
1280 }
1281
1282 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001283 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284 arg_had_last = TRUE;
1285
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001286 /* Edit the file; always use the last known line number.
1287 * When it fails (e.g. Abort for already edited file) restore the
1288 * argument index. */
1289 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001290 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02001291 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001292 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001293 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001295 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296 setmark('\'');
1297 }
1298}
1299
1300/*
1301 * ":next", and commands that behave like it.
1302 */
1303 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001304ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305{
1306 int i;
1307
1308 /*
1309 * check for changed buffer now, if this fails the argument list is not
1310 * redefined.
1311 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02001312 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001314 || !check_changed(curbuf, CCGD_AW
1315 | (eap->forceit ? CCGD_FORCEIT : 0)
1316 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317 {
1318 if (*eap->arg != NUL) /* redefine file list */
1319 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001320 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321 return;
1322 i = 0;
1323 }
1324 else
1325 i = curwin->w_arg_idx + (int)eap->line2;
1326 do_argfile(eap, i);
1327 }
1328}
1329
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330/*
1331 * ":argedit"
1332 */
1333 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001334ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001335{
Bram Moolenaar90305c62017-07-16 15:31:17 +02001336 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001337 // Whether curbuf will be reused, curbuf->b_ffname will be set.
1338 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001340 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02001341 return;
1342#ifdef FEAT_TITLE
1343 maketitle();
1344#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001345
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001346 if (curwin->w_arg_idx == 0
1347 && (curbuf->b_ml.ml_flags & ML_EMPTY)
1348 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02001349 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02001351 if (i < ARGCOUNT)
1352 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353}
1354
1355/*
1356 * ":argadd"
1357 */
1358 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001359ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001360{
1361 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001362 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
1363 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001364#ifdef FEAT_TITLE
1365 maketitle();
1366#endif
1367}
1368
1369/*
1370 * ":argdelete"
1371 */
1372 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001373ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001374{
1375 int i;
1376 int n;
1377
1378 if (eap->addr_count > 0)
1379 {
1380 /* ":1,4argdel": Delete all arguments in the range. */
1381 if (eap->line2 > ARGCOUNT)
1382 eap->line2 = ARGCOUNT;
1383 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01001384 if (*eap->arg != NUL)
1385 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001386 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01001387 else if (n <= 0)
1388 {
1389 /* Don't give an error for ":%argdel" if the list is empty. */
1390 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001391 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01001392 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001393 else
1394 {
1395 for (i = eap->line1; i <= eap->line2; ++i)
1396 vim_free(ARGLIST[i - 1].ae_fname);
1397 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
1398 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
1399 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001400 if (curwin->w_arg_idx >= eap->line2)
1401 curwin->w_arg_idx -= n;
1402 else if (curwin->w_arg_idx > eap->line1)
1403 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01001404 if (ARGCOUNT == 0)
1405 curwin->w_arg_idx = 0;
1406 else if (curwin->w_arg_idx >= ARGCOUNT)
1407 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001408 }
1409 }
1410 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001411 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001412 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001413 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414#ifdef FEAT_TITLE
1415 maketitle();
1416#endif
1417}
1418
1419/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001420 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001421 */
1422 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001423ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424{
1425 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001426 win_T *wp;
1427 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01001428 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001430#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001432#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001433 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001434#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02001435 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001436 int qf_idx;
1437#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01001439#ifndef FEAT_QUICKFIX
1440 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
1441 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1442 {
1443 ex_ni(eap);
1444 return;
1445 }
1446#endif
1447
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001448#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001449 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001450 {
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00001451 /* Don't do syntax HL autocommands. Skipping the syntax file is a
1452 * great speed improvement. */
1453 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001454
1455 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1456 buf->b_flags &= ~BF_SYN_SET;
1457 buf = curbuf;
1458 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001459#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001460#ifdef FEAT_CLIPBOARD
1461 start_global_changes();
1462#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001463
1464 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001465 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02001466 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001467 || !check_changed(curbuf, CCGD_AW
1468 | (eap->forceit ? CCGD_FORCEIT : 0)
1469 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001471 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001472 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001473 wp = firstwin;
1474 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001475 switch (eap->cmdidx)
1476 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01001477 case CMD_windo:
1478 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
1479 i++;
1480 break;
1481 case CMD_tabdo:
1482 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
1483 i++;
1484 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001485 case CMD_argdo:
1486 i = eap->line1 - 1;
1487 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001488 default:
1489 break;
1490 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491 /* set pcmark now */
1492 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001493 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01001494 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001495 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01001496 || !buf->b_p_bl); buf = buf->b_next)
1497 if (buf->b_fnum > eap->line2)
1498 {
1499 buf = NULL;
1500 break;
1501 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001502 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01001503 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001504 }
1505#ifdef FEAT_QUICKFIX
1506 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1507 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1508 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02001509 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001510 if (qf_size <= 0 || eap->line1 > qf_size)
1511 buf = NULL;
1512 else
1513 {
1514 ex_cc(eap);
1515
1516 buf = curbuf;
1517 i = eap->line1 - 1;
1518 if (eap->addr_count <= 0)
1519 /* default is all the quickfix/location list entries */
1520 eap->line2 = qf_size;
1521 }
1522 }
1523#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001524 else
1525 setpcmark();
1526 listcmd_busy = TRUE; /* avoids setting pcmark below */
1527
Bram Moolenaare25bb902015-02-27 20:33:37 +01001528 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001529 {
1530 if (eap->cmdidx == CMD_argdo)
1531 {
1532 /* go to argument "i" */
1533 if (i == ARGCOUNT)
1534 break;
1535 /* Don't call do_argfile() when already there, it will try
1536 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001537 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001538 {
1539 /* Clear 'shm' to avoid that the file message overwrites
1540 * any output from the command. */
1541 p_shm_save = vim_strsave(p_shm);
1542 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001543 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001544 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1545 vim_free(p_shm_save);
1546 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 if (curwin->w_arg_idx != i)
1548 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 else if (eap->cmdidx == CMD_windo)
1551 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001552 /* go to window "wp" */
1553 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001554 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001555 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00001556 if (curwin != wp)
1557 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001558 wp = curwin->w_next;
1559 }
1560 else if (eap->cmdidx == CMD_tabdo)
1561 {
1562 /* go to window "tp" */
1563 if (!valid_tabpage(tp))
1564 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02001565 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001566 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568 else if (eap->cmdidx == CMD_bufdo)
1569 {
1570 /* Remember the number of the next listed buffer, in case
1571 * ":bwipe" is used or autocommands do something strange. */
1572 next_fnum = -1;
1573 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
1574 if (buf->b_p_bl)
1575 {
1576 next_fnum = buf->b_fnum;
1577 break;
1578 }
1579 }
1580
Bram Moolenaara162bc52015-01-07 16:54:21 +01001581 ++i;
1582
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583 /* execute the command */
1584 do_cmdline(eap->arg, eap->getline, eap->cookie,
1585 DOCMD_VERBOSE + DOCMD_NOWAIT);
1586
1587 if (eap->cmdidx == CMD_bufdo)
1588 {
1589 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01001590 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001591 break;
1592 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001593 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594 if (buf->b_fnum == next_fnum)
1595 break;
1596 if (buf == NULL)
1597 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001598
1599 /* Go to the next buffer. Clear 'shm' to avoid that the file
1600 * message overwrites any output from the command. */
1601 p_shm_save = vim_strsave(p_shm);
1602 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001604 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1605 vim_free(p_shm_save);
1606
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001607 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 if (curbuf->b_fnum != next_fnum)
1609 break;
1610 }
1611
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001612#ifdef FEAT_QUICKFIX
1613 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1614 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1615 {
1616 if (i >= qf_size || i >= eap->line2)
1617 break;
1618
1619 qf_idx = qf_get_cur_idx(eap);
1620
1621 ex_cnext(eap);
1622
1623 /* If jumping to the next quickfix entry fails, quit here */
1624 if (qf_get_cur_idx(eap) == qf_idx)
1625 break;
1626 }
1627#endif
1628
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629 if (eap->cmdidx == CMD_windo)
1630 {
1631 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01001632
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633 /* required when 'scrollbind' has been set */
1634 if (curwin->w_p_scb)
1635 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01001637
Bram Moolenaara162bc52015-01-07 16:54:21 +01001638 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
1639 if (i+1 > eap->line2)
1640 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001641 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
1642 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001643 }
1644 listcmd_busy = FALSE;
1645 }
1646
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001647#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001648 if (save_ei != NULL)
1649 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001650 buf_T *bnext;
1651 aco_save_T aco;
1652
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001653 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001654
1655 for (buf = firstbuf; buf != NULL; buf = bnext)
1656 {
1657 bnext = buf->b_next;
1658 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
1659 {
1660 buf->b_flags &= ~BF_SYN_SET;
1661
1662 // buffer was opened while Syntax autocommands were disabled,
1663 // need to trigger them now.
1664 if (buf == curbuf)
1665 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001666 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001667 else
1668 {
1669 aucmd_prepbuf(&aco, buf);
1670 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
1671 buf->b_fname, TRUE, buf);
1672 aucmd_restbuf(&aco);
1673 }
1674
1675 // start over, in case autocommands messed things up.
1676 bnext = firstbuf;
1677 }
1678 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001679 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001681#ifdef FEAT_CLIPBOARD
1682 end_global_changes();
1683#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684}
1685
1686/*
1687 * Add files[count] to the arglist of the current window after arg "after".
1688 * The file names in files[count] must have been allocated and are taken over.
1689 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001691 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001692alist_add_list(
1693 int count,
1694 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001695 int after, // where to add: 0 = before first one
1696 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697{
1698 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01001699 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001700
1701 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
1702 {
1703 if (after < 0)
1704 after = 0;
1705 if (after > ARGCOUNT)
1706 after = ARGCOUNT;
1707 if (after < ARGCOUNT)
1708 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
1709 (ARGCOUNT - after) * sizeof(aentry_T));
1710 for (i = 0; i < count; ++i)
1711 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001712 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
1713
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001715 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716 }
1717 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01001718 if (old_argcount > 0 && curwin->w_arg_idx >= after)
1719 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001720 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721 }
1722
1723 for (i = 0; i < count; ++i)
1724 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725}
1726
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02001727#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1728/*
1729 * Function given to ExpandGeneric() to obtain the possible arguments of the
1730 * argedit and argdelete commands.
1731 */
1732 char_u *
1733get_arglist_name(expand_T *xp UNUSED, int idx)
1734{
1735 if (idx >= ARGCOUNT)
1736 return NULL;
1737
1738 return alist_name(&ARGLIST[idx]);
1739}
1740#endif
1741
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001742
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743#ifdef FEAT_EVAL
1744/*
1745 * ":compiler[!] {name}"
1746 */
1747 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001748ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749{
1750 char_u *buf;
1751 char_u *old_cur_comp = NULL;
1752 char_u *p;
1753
1754 if (*eap->arg == NUL)
1755 {
1756 /* List all compiler scripts. */
1757 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1758 /* ) keep the indenter happy... */
1759 }
1760 else
1761 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02001762 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 if (buf != NULL)
1764 {
1765 if (eap->forceit)
1766 {
1767 /* ":compiler! {name}" sets global options */
1768 do_cmdline_cmd((char_u *)
1769 "command -nargs=* CompilerSet set <args>");
1770 }
1771 else
1772 {
1773 /* ":compiler! {name}" sets local options.
1774 * To remain backwards compatible "current_compiler" is always
1775 * used. A user's compiler plugin may set it, the distributed
1776 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001777 * "b:current_compiler" and restore "current_compiler".
1778 * Explicitly prepend "g:" to make it work in a function. */
1779 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780 if (old_cur_comp != NULL)
1781 old_cur_comp = vim_strsave(old_cur_comp);
1782 do_cmdline_cmd((char_u *)
1783 "command -nargs=* CompilerSet setlocal <args>");
1784 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001785 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00001786 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001787
1788 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001789 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001790 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 vim_free(buf);
1792
1793 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1794
1795 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001796 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 if (p != NULL)
1798 set_internal_string_var((char_u *)"b:current_compiler", p);
1799
1800 /* Restore "current_compiler" for ":compiler {name}". */
1801 if (!eap->forceit)
1802 {
1803 if (old_cur_comp != NULL)
1804 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001805 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 old_cur_comp);
1807 vim_free(old_cur_comp);
1808 }
1809 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001810 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811 }
1812 }
1813 }
1814}
1815#endif
1816
1817/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001818 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 */
1820 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001821ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001823 char_u *arg = eap->arg;
1824 char_u *p = skiptowhite(arg);
1825 int len = (int)(p - arg);
1826 int flags = eap->forceit ? DIP_ALL : 0;
1827
1828 if (STRNCMP(arg, "START", len) == 0)
1829 {
1830 flags += DIP_START + DIP_NORTP;
1831 arg = skipwhite(arg + len);
1832 }
1833 else if (STRNCMP(arg, "OPT", len) == 0)
1834 {
1835 flags += DIP_OPT + DIP_NORTP;
1836 arg = skipwhite(arg + len);
1837 }
1838 else if (STRNCMP(arg, "PACK", len) == 0)
1839 {
1840 flags += DIP_START + DIP_OPT + DIP_NORTP;
1841 arg = skipwhite(arg + len);
1842 }
1843 else if (STRNCMP(arg, "ALL", len) == 0)
1844 {
1845 flags += DIP_START + DIP_OPT;
1846 arg = skipwhite(arg + len);
1847 }
1848
1849 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850}
1851
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001853source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001855 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001856}
1857
1858/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001859 * Find the file "name" in all directories in "path" and invoke
1860 * "callback(fname, cookie)".
1861 * "name" can contain wildcards.
1862 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
1863 * When "flags" has DIP_DIR: find directories instead of files.
1864 * When "flags" has DIP_ERR: give an error message if there is no match.
1865 *
1866 * return FAIL when no file could be sourced, OK otherwise.
1867 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01001868 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001869do_in_path(
1870 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001871 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01001872 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001873 void (*callback)(char_u *fname, void *ck),
1874 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875{
1876 char_u *rtp;
1877 char_u *np;
1878 char_u *buf;
1879 char_u *rtp_copy;
1880 char_u *tail;
1881 int num_files;
1882 char_u **files;
1883 int i;
1884 int did_one = FALSE;
1885#ifdef AMIGA
1886 struct Process *proc = (struct Process *)FindTask(0L);
1887 APTR save_winptr = proc->pr_WindowPtr;
1888
1889 /* Avoid a requester here for a volume that doesn't exist. */
1890 proc->pr_WindowPtr = (APTR)-1L;
1891#endif
1892
1893 /* Make a copy of 'runtimepath'. Invoking the callback may change the
1894 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001895 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 buf = alloc(MAXPATHL);
1897 if (buf != NULL && rtp_copy != NULL)
1898 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001899 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001900 {
1901 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001902 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001903 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001904 verbose_leave();
1905 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001906
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 /* Loop over all entries in 'runtimepath'. */
1908 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01001909 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02001911 size_t buflen;
1912
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 /* Copy the path from 'runtimepath' to buf[]. */
1914 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02001915 buflen = STRLEN(buf);
1916
1917 /* Skip after or non-after directories. */
1918 if (flags & (DIP_NOAFTER | DIP_AFTER))
1919 {
1920 int is_after = buflen >= 5
1921 && STRCMP(buf + buflen - 5, "after") == 0;
1922
1923 if ((is_after && (flags & DIP_NOAFTER))
1924 || (!is_after && (flags & DIP_AFTER)))
1925 continue;
1926 }
1927
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001928 if (name == NULL)
1929 {
1930 (*callback)(buf, (void *) &cookie);
1931 if (!did_one)
1932 did_one = (cookie == NULL);
1933 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02001934 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 {
1936 add_pathsep(buf);
1937 tail = buf + STRLEN(buf);
1938
1939 /* Loop over all patterns in "name" */
1940 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01001941 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 {
1943 /* Append the pattern from "name" to buf[]. */
1944 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
1945 "\t ");
1946
1947 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001948 {
1949 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001950 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001951 verbose_leave();
1952 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953
1954 /* Expand wildcards, invoke the callback for each match. */
1955 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01001956 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 {
1958 for (i = 0; i < num_files; ++i)
1959 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001960 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01001962 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963 break;
1964 }
1965 FreeWild(num_files, files);
1966 }
1967 }
1968 }
1969 }
1970 }
1971 vim_free(buf);
1972 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001973 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001974 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001975 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
1976
1977 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001978 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001979 else if (p_verbose > 0)
1980 {
1981 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001982 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001983 verbose_leave();
1984 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001985 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986
1987#ifdef AMIGA
1988 proc->pr_WindowPtr = save_winptr;
1989#endif
1990
1991 return did_one ? OK : FAIL;
1992}
1993
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001994/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001995 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001996 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001997 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
1998 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001999 * Returns OK when at least one match found, FAIL otherwise.
2000 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002001 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002002 * passed by reference in this case, setting it to NULL indicates that callback
2003 * has done its job.
2004 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002005 static int
2006do_in_path_and_pp(
2007 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002008 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002009 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002010 void (*callback)(char_u *fname, void *ck),
2011 void *cookie)
2012{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002013 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002014 char_u *s;
2015 int len;
2016 char *start_dir = "pack/*/start/*/%s";
2017 char *opt_dir = "pack/*/opt/*/%s";
2018
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002019 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002020 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002021
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002022 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002023 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002024 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002025 s = alloc(len);
2026 if (s == NULL)
2027 return FAIL;
2028 vim_snprintf((char *)s, len, start_dir, name);
2029 done = do_in_path(p_pp, s, flags, callback, cookie);
2030 vim_free(s);
2031 }
2032
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002033 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002034 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002035 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002036 s = alloc(len);
2037 if (s == NULL)
2038 return FAIL;
2039 vim_snprintf((char *)s, len, opt_dir, name);
2040 done = do_in_path(p_pp, s, flags, callback, cookie);
2041 vim_free(s);
2042 }
2043
2044 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002045}
2046
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002047/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002048 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2049 */
2050 int
2051do_in_runtimepath(
2052 char_u *name,
2053 int flags,
2054 void (*callback)(char_u *fname, void *ck),
2055 void *cookie)
2056{
2057 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2058}
2059
2060/*
2061 * Source the file "name" from all directories in 'runtimepath'.
2062 * "name" can contain wildcards.
2063 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2064 *
2065 * return FAIL when no file could be sourced, OK otherwise.
2066 */
2067 int
2068source_runtime(char_u *name, int flags)
2069{
2070 return source_in_path(p_rtp, name, flags);
2071}
2072
2073/*
2074 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2075 */
2076 int
2077source_in_path(char_u *path, char_u *name, int flags)
2078{
2079 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2080}
2081
2082
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002083#if defined(FEAT_EVAL) || defined(PROTO)
2084
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002085/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002086 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002087 */
2088 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002089source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002090{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002091 int num_files;
2092 char_u **files;
2093 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002094
Bram Moolenaarf3654822016-03-04 22:12:23 +01002095 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002096 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002097 for (i = 0; i < num_files; ++i)
2098 (void)do_source(files[i], FALSE, DOSO_NONE);
2099 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002100 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002101}
2102
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002103/*
2104 * Add the package directory to 'runtimepath'.
2105 */
2106 static int
2107add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002108{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002109 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002110 char_u *entry;
2111 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002112 int c;
2113 char_u *new_rtp;
2114 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002115 size_t oldlen;
2116 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002117 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002118 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002119 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002120 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002121 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002122 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002123 char_u *buf = NULL;
2124 char_u *rtp_ffname;
2125 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002126 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002127
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002128 p4 = p3 = p2 = p1 = get_past_head(fname);
2129 for (p = p1; *p; MB_PTR_ADV(p))
2130 if (vim_ispathsep_nocolon(*p))
2131 {
2132 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2133 }
2134
2135 /* now we have:
2136 * rtp/pack/name/start/name
2137 * p4 p3 p2 p1
2138 *
2139 * find the part up to "pack" in 'runtimepath' */
2140 c = *++p4; /* append pathsep in order to expand symlink */
2141 *p4 = NUL;
2142 ffname = fix_fname(fname);
2143 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002144 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002145 return FAIL;
2146
Bram Moolenaar99396d42018-09-08 18:21:16 +02002147 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2148 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002149 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002150 buf = alloc(MAXPATHL);
2151 if (buf == NULL)
2152 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002153 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002154 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002155 char_u *cur_entry = entry;
2156
2157 copy_option_part(&entry, buf, MAXPATHL, ",");
2158 if (insp == NULL)
2159 {
2160 add_pathsep(buf);
2161 rtp_ffname = fix_fname(buf);
2162 if (rtp_ffname == NULL)
2163 goto theend;
2164 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2165 vim_free(rtp_ffname);
2166 if (match)
2167 // Insert "ffname" after this entry (and comma).
2168 insp = entry;
2169 }
2170
2171 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2172 && p > buf
2173 && vim_ispathsep(p[-1])
2174 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2175 {
2176 if (insp == NULL)
2177 // Did not find "ffname" before the first "after" directory,
2178 // insert it before this entry.
2179 insp = cur_entry;
2180 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002181 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002182 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002183 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002184
Bram Moolenaar99396d42018-09-08 18:21:16 +02002185 if (insp == NULL)
2186 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002187 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002188
Bram Moolenaar99396d42018-09-08 18:21:16 +02002189 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002190 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2191 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002192 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002193
2194 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002195 addlen = STRLEN(fname) + 1; // add one for comma
Bram Moolenaar51e14382019-05-25 20:21:28 +02002196 new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002197 if (new_rtp == NULL)
2198 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002199
2200 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2201 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002202 keep = (int)(insp - p_rtp);
2203 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002204 new_rtp_len = keep;
2205 if (*insp == NUL)
2206 new_rtp[new_rtp_len++] = ','; // add comma before
2207 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2208 new_rtp_len += addlen - 1;
2209 if (*insp != NUL)
2210 new_rtp[new_rtp_len++] = ','; // add comma after
2211
2212 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002213 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002214 int keep_after = (int)(after_insp - p_rtp);
2215
2216 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2217 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2218 keep_after - keep);
2219 new_rtp_len += keep_after - keep;
2220 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2221 new_rtp_len += afterlen - 1;
2222 new_rtp[new_rtp_len++] = ',';
2223 keep = keep_after;
2224 }
2225
2226 if (p_rtp[keep] != NUL)
2227 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2228 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2229 else
2230 new_rtp[new_rtp_len] = NUL;
2231
2232 if (afterlen > 0 && after_insp == NULL)
2233 {
2234 // Append afterdir when "after" was not found:
2235 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002236 STRCAT(new_rtp, ",");
2237 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002238 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002239
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002240 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2241 vim_free(new_rtp);
2242 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002243
2244theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002245 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002246 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002247 vim_free(afterdir);
2248 return retval;
2249}
2250
2251/*
2252 * Load scripts in "plugin" and "ftdetect" directories of the package.
2253 */
2254 static int
2255load_pack_plugin(char_u *fname)
2256{
2257 static char *plugpat = "%s/plugin/**/*.vim";
2258 static char *ftpat = "%s/ftdetect/*.vim";
2259 int len;
2260 char_u *ffname = fix_fname(fname);
2261 char_u *pat = NULL;
2262 int retval = FAIL;
2263
2264 if (ffname == NULL)
2265 return FAIL;
2266 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2267 pat = alloc(len);
2268 if (pat == NULL)
2269 goto theend;
2270 vim_snprintf((char *)pat, len, plugpat, ffname);
2271 source_all_matches(pat);
2272
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002273 {
2274 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2275
2276 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2277 * found when it loads. */
2278 if (cmd != NULL && eval_to_number(cmd) > 0)
2279 {
2280 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2281 vim_snprintf((char *)pat, len, ftpat, ffname);
2282 source_all_matches(pat);
2283 do_cmdline_cmd((char_u *)"augroup END");
2284 }
2285 vim_free(cmd);
2286 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002287 vim_free(pat);
2288 retval = OK;
2289
2290theend:
2291 vim_free(ffname);
2292 return retval;
2293}
2294
2295/* used for "cookie" of add_pack_plugin() */
2296static int APP_ADD_DIR;
2297static int APP_LOAD;
2298static int APP_BOTH;
2299
2300 static void
2301add_pack_plugin(char_u *fname, void *cookie)
2302{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002303 if (cookie != &APP_LOAD)
2304 {
2305 char_u *buf = alloc(MAXPATHL);
2306 char_u *p;
2307 int found = FALSE;
2308
2309 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002310 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002311 p = p_rtp;
2312 while (*p != NUL)
2313 {
2314 copy_option_part(&p, buf, MAXPATHL, ",");
2315 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2316 {
2317 found = TRUE;
2318 break;
2319 }
2320 }
2321 vim_free(buf);
2322 if (!found)
2323 /* directory is not yet in 'runtimepath', add it */
2324 if (add_pack_dir_to_rtp(fname) == FAIL)
2325 return;
2326 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002327
2328 if (cookie != &APP_ADD_DIR)
2329 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002330}
2331
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002332/*
2333 * Add all packages in the "start" directory to 'runtimepath'.
2334 */
2335 void
2336add_pack_start_dirs(void)
2337{
2338 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2339 add_pack_plugin, &APP_ADD_DIR);
2340}
2341
2342/*
2343 * Load plugins from all packages in the "start" directory.
2344 */
2345 void
2346load_start_packages(void)
2347{
2348 did_source_packages = TRUE;
2349 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2350 add_pack_plugin, &APP_LOAD);
2351}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002352
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002353/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002354 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002355 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002356 */
2357 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002358ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002359{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002360 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002361 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002362 /* First do a round to add all directories to 'runtimepath', then load
2363 * the plugins. This allows for plugins to use an autoload directory
2364 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002365 add_pack_start_dirs();
2366 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002367 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002368}
2369
2370/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002371 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002372 */
2373 void
2374ex_packadd(exarg_T *eap)
2375{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002376 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002377 int len;
2378 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002379 int round;
2380 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002381
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002382 /* Round 1: use "start", round 2: use "opt". */
2383 for (round = 1; round <= 2; ++round)
2384 {
2385 /* Only look under "start" when loading packages wasn't done yet. */
2386 if (round == 1 && did_source_packages)
2387 continue;
2388
2389 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002390 pat = alloc(len);
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002391 if (pat == NULL)
2392 return;
2393 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
2394 /* The first round don't give a "not found" error, in the second round
2395 * only when nothing was found in the first round. */
2396 res = do_in_path(p_pp, (char_u *)pat,
2397 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
2398 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
2399 vim_free(pat);
2400 }
Bram Moolenaar91715872016-03-03 17:13:03 +01002401}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002402#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01002403
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002404#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405/*
2406 * ":options"
2407 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002409ex_options(
2410 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411{
Bram Moolenaare0b59492019-05-21 20:54:45 +02002412 vim_setenv((char_u *)"OPTWIN_CMD",
2413 (char_u *)(cmdmod.tab ? "tab"
2414 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2416}
2417#endif
2418
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002419#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
2420
2421# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
2422/*
2423 * Detect Python 3 or 2, and initialize 'pyxversion'.
2424 */
2425 void
2426init_pyxversion(void)
2427{
2428 if (p_pyx == 0)
2429 {
2430 if (python3_enabled(FALSE))
2431 p_pyx = 3;
2432 else if (python_enabled(FALSE))
2433 p_pyx = 2;
2434 }
2435}
2436# endif
2437
2438/*
2439 * Does a file contain one of the following strings at the beginning of any
2440 * line?
2441 * "#!(any string)python2" => returns 2
2442 * "#!(any string)python3" => returns 3
2443 * "# requires python 2.x" => returns 2
2444 * "# requires python 3.x" => returns 3
2445 * otherwise return 0.
2446 */
2447 static int
2448requires_py_version(char_u *filename)
2449{
2450 FILE *file;
2451 int requires_py_version = 0;
2452 int i, lines;
2453
2454 lines = (int)p_mls;
2455 if (lines < 0)
2456 lines = 5;
2457
2458 file = mch_fopen((char *)filename, "r");
2459 if (file != NULL)
2460 {
2461 for (i = 0; i < lines; i++)
2462 {
2463 if (vim_fgets(IObuff, IOSIZE, file))
2464 break;
2465 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
2466 {
2467 /* Check shebang. */
2468 if (strstr((char *)IObuff + 2, "python2") != NULL)
2469 {
2470 requires_py_version = 2;
2471 break;
2472 }
2473 if (strstr((char *)IObuff + 2, "python3") != NULL)
2474 {
2475 requires_py_version = 3;
2476 break;
2477 }
2478 }
2479 IObuff[21] = '\0';
2480 if (STRCMP("# requires python 2.x", IObuff) == 0)
2481 {
2482 requires_py_version = 2;
2483 break;
2484 }
2485 if (STRCMP("# requires python 3.x", IObuff) == 0)
2486 {
2487 requires_py_version = 3;
2488 break;
2489 }
2490 }
2491 fclose(file);
2492 }
2493 return requires_py_version;
2494}
2495
2496
2497/*
2498 * Source a python file using the requested python version.
2499 */
2500 static void
2501source_pyx_file(exarg_T *eap, char_u *fname)
2502{
2503 exarg_T ex;
2504 int v = requires_py_version(fname);
2505
2506# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2507 init_pyxversion();
2508# endif
2509 if (v == 0)
2510 {
2511# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2512 /* user didn't choose a preference, 'pyx' is used */
2513 v = p_pyx;
2514# elif defined(FEAT_PYTHON)
2515 v = 2;
2516# elif defined(FEAT_PYTHON3)
2517 v = 3;
2518# endif
2519 }
2520
2521 /*
2522 * now source, if required python version is not supported show
2523 * unobtrusive message.
2524 */
2525 if (eap == NULL)
2526 vim_memset(&ex, 0, sizeof(ex));
2527 else
2528 ex = *eap;
2529 ex.arg = fname;
2530 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
2531
2532 if (v == 2)
2533 {
2534# ifdef FEAT_PYTHON
2535 ex_pyfile(&ex);
2536# else
2537 vim_snprintf((char *)IObuff, IOSIZE,
2538 _("W20: Required python version 2.x not supported, ignoring file: %s"),
2539 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002540 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002541# endif
2542 return;
2543 }
2544 else
2545 {
2546# ifdef FEAT_PYTHON3
2547 ex_py3file(&ex);
2548# else
2549 vim_snprintf((char *)IObuff, IOSIZE,
2550 _("W21: Required python version 3.x not supported, ignoring file: %s"),
2551 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002552 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002553# endif
2554 return;
2555 }
2556}
2557
2558/*
2559 * ":pyxfile {fname}"
2560 */
2561 void
2562ex_pyxfile(exarg_T *eap)
2563{
2564 source_pyx_file(eap, eap->arg);
2565}
2566
2567/*
2568 * ":pyx"
2569 */
2570 void
2571ex_pyx(exarg_T *eap)
2572{
2573# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2574 init_pyxversion();
2575 if (p_pyx == 2)
2576 ex_python(eap);
2577 else
2578 ex_py3(eap);
2579# elif defined(FEAT_PYTHON)
2580 ex_python(eap);
2581# elif defined(FEAT_PYTHON3)
2582 ex_py3(eap);
2583# endif
2584}
2585
2586/*
2587 * ":pyxdo"
2588 */
2589 void
2590ex_pyxdo(exarg_T *eap)
2591{
2592# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2593 init_pyxversion();
2594 if (p_pyx == 2)
2595 ex_pydo(eap);
2596 else
2597 ex_py3do(eap);
2598# elif defined(FEAT_PYTHON)
2599 ex_pydo(eap);
2600# elif defined(FEAT_PYTHON3)
2601 ex_py3do(eap);
2602# endif
2603}
2604
2605#endif
2606
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607/*
2608 * ":source {fname}"
2609 */
2610 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002611ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612{
2613#ifdef FEAT_BROWSE
2614 if (cmdmod.browse)
2615 {
2616 char_u *fname = NULL;
2617
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002618 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02002619 NULL, NULL,
2620 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621 if (fname != NULL)
2622 {
2623 cmd_source(fname, eap);
2624 vim_free(fname);
2625 }
2626 }
2627 else
2628#endif
2629 cmd_source(eap->arg, eap);
2630}
2631
2632 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002633cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002634{
2635 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002636 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637
Bram Moolenaar071d4272004-06-13 20:20:40 +00002638 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002639 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002640 * Need to execute the commands directly. This is required at least
2641 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642 * - ":g" command busy
2643 * - after ":argdo", ":windo" or ":bufdo"
2644 * - another command follows
2645 * - inside a loop
2646 */
2647 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2648#ifdef FEAT_EVAL
2649 || eap->cstack->cs_idx >= 0
2650#endif
2651 );
2652
2653 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002654 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002655 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656}
2657
2658/*
2659 * ":source" and associated commands.
2660 */
2661/*
2662 * Structure used to store info for each sourced file.
2663 * It is shared between do_source() and getsourceline().
2664 * This is required, because it needs to be handed to do_cmdline() and
2665 * sourcing can be done recursively.
2666 */
2667struct source_cookie
2668{
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002669 FILE *fp; // opened file for sourcing
2670 char_u *nextline; // if not NULL: line that was read ahead
2671 linenr_T sourcing_lnum; // line number of the source file
2672 int finished; // ":finish" used
Bram Moolenaar00590742019-02-15 21:06:09 +01002673#ifdef USE_CRNL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002674 int fileformat; // EOL_UNKNOWN, EOL_UNIX or EOL_DOS
2675 int error; // TRUE if LF found after CR-LF
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676#endif
2677#ifdef FEAT_EVAL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002678 linenr_T breakpoint; // next line with breakpoint or zero
2679 char_u *fname; // name of sourced file
2680 int dbg_tick; // debug_tick when breakpoint was set
2681 int level; // top nesting level of sourced file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002683 vimconv_T conv; // type of conversion
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684};
2685
2686#ifdef FEAT_EVAL
2687/*
2688 * Return the address holding the next breakpoint line for a source cookie.
2689 */
2690 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002691source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692{
2693 return &((struct source_cookie *)cookie)->breakpoint;
2694}
2695
2696/*
2697 * Return the address holding the debug tick for a source cookie.
2698 */
2699 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002700source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701{
2702 return &((struct source_cookie *)cookie)->dbg_tick;
2703}
2704
2705/*
2706 * Return the nesting level for a source cookie.
2707 */
2708 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002709source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710{
2711 return ((struct source_cookie *)cookie)->level;
2712}
2713#endif
2714
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002715static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716
Bram Moolenaar4f974752019-02-17 17:44:42 +01002717#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002718# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002719/*
2720 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002721 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 */
2723 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002724fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725{
Bram Moolenaar4f974752019-02-17 17:44:42 +01002726# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002727 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2728# else
2729 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002730# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731
2732 if (fd_tmp == -1)
2733 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002734
2735# ifdef HAVE_FD_CLOEXEC
2736 {
2737 int fdflags = fcntl(fd_tmp, F_GETFD);
2738 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02002739 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002740 }
2741# endif
2742
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 return fdopen(fd_tmp, READBIN);
2744}
2745#endif
2746
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747/*
2748 * do_source: Read the file "fname" and execute its lines as EX commands.
2749 *
2750 * This function may be called recursively!
2751 *
2752 * return FAIL if file could not be opened, OK otherwise
2753 */
2754 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002755do_source(
2756 char_u *fname,
2757 int check_other, /* check for .vimrc and _vimrc */
2758 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759{
2760 struct source_cookie cookie;
2761 char_u *save_sourcing_name;
2762 linenr_T save_sourcing_lnum;
2763 char_u *p;
2764 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002765 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 int retval = FAIL;
2767#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002768 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002770 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002771 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002773 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02002775 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 int stat_ok;
2777# endif
2778#endif
2779#ifdef STARTUPTIME
2780 struct timeval tv_rel;
2781 struct timeval tv_start;
2782#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002783#ifdef FEAT_PROFILE
2784 proftime_T wait_start;
2785#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002786 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787
Bram Moolenaar071d4272004-06-13 20:20:40 +00002788 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002789 if (p == NULL)
2790 return retval;
2791 fname_exp = fix_fname(p);
2792 vim_free(p);
2793 if (fname_exp == NULL)
2794 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795 if (mch_isdir(fname_exp))
2796 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002797 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798 goto theend;
2799 }
2800
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002801 /* Apply SourceCmd autocommands, they should get the file and source it. */
2802 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2803 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2804 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002805 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002806#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002807 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002808#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002809 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002810#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002811 if (retval == OK)
2812 // Apply SourcePost autocommands.
2813 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
2814 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002815 goto theend;
2816 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002817
2818 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002819 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002820
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002821#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2823#else
2824 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2825#endif
2826 if (cookie.fp == NULL && check_other)
2827 {
2828 /*
2829 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2830 * and ".exrc" by "_exrc" or vice versa.
2831 */
2832 p = gettail(fname_exp);
2833 if ((*p == '.' || *p == '_')
2834 && (STRICMP(p + 1, "vimrc") == 0
2835 || STRICMP(p + 1, "gvimrc") == 0
2836 || STRICMP(p + 1, "exrc") == 0))
2837 {
2838 if (*p == '_')
2839 *p = '.';
2840 else
2841 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002842#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2844#else
2845 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2846#endif
2847 }
2848 }
2849
2850 if (cookie.fp == NULL)
2851 {
2852 if (p_verbose > 0)
2853 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002854 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002856 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002858 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002859 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002860 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 }
2862 goto theend;
2863 }
2864
2865 /*
2866 * The file exists.
2867 * - In verbose mode, give a message.
2868 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2869 */
2870 if (p_verbose > 1)
2871 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002872 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002874 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002876 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002877 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002878 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002880 if (is_vimrc == DOSO_VIMRC)
2881 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2882 else if (is_vimrc == DOSO_GVIMRC)
2883 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884
2885#ifdef USE_CRNL
2886 /* If no automatic file format: Set default to CR-NL. */
2887 if (*p_ffs == NUL)
2888 cookie.fileformat = EOL_DOS;
2889 else
2890 cookie.fileformat = EOL_UNKNOWN;
2891 cookie.error = FALSE;
2892#endif
2893
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894 cookie.nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002895 cookie.sourcing_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896 cookie.finished = FALSE;
2897
2898#ifdef FEAT_EVAL
2899 /*
2900 * Check if this script has a breakpoint.
2901 */
2902 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2903 cookie.fname = fname_exp;
2904 cookie.dbg_tick = debug_tick;
2905
2906 cookie.level = ex_nesting_level;
2907#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908
2909 /*
2910 * Keep the sourcing name/lnum, for recursive calls.
2911 */
2912 save_sourcing_name = sourcing_name;
2913 sourcing_name = fname_exp;
2914 save_sourcing_lnum = sourcing_lnum;
2915 sourcing_lnum = 0;
2916
2917#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01002918 if (time_fd != NULL)
2919 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920#endif
2921
2922#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00002923# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002924 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002925 prof_child_enter(&wait_start); /* entering a child now */
2926# endif
2927
2928 /* Don't use local function variables, if called from a function.
2929 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002930 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002931
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002932 save_current_sctx = current_sctx;
2933 current_sctx.sc_lnum = 0;
2934 current_sctx.sc_version = 1;
2935
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002936 // Check if this script was sourced before to finds its SID.
2937 // If it's new, generate a new SID.
2938 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002939 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940# ifdef UNIX
2941 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2942# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002943 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
2944 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002945 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002946 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002947 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948 && (
2949# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00002950 /* Compare dev/ino when possible, it catches symbolic
2951 * links. Also compare file names, the inode may change
2952 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002953 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002954 && (si->sn_dev == st.st_dev
2955 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002957 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002959 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002960 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002961 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002962 current_sctx.sc_sid = ++last_current_SID;
2963 if (ga_grow(&script_items,
2964 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002965 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002966 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002968 ++script_items.ga_len;
2969 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
2970# ifdef FEAT_PROFILE
2971 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002974 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002975 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01002976 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00002977# ifdef UNIX
2978 if (stat_ok)
2979 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002980 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002981 si->sn_dev = st.st_dev;
2982 si->sn_ino = st.st_ino;
2983 }
2984 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002985 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002986# endif
2987
Bram Moolenaar071d4272004-06-13 20:20:40 +00002988 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002989 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 }
2991
Bram Moolenaar05159a02005-02-26 23:04:13 +00002992# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002993 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002994 {
2995 int forceit;
2996
2997 /* Check if we do profiling for this script. */
2998 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
2999 {
3000 script_do_profile(si);
3001 si->sn_pr_force = forceit;
3002 }
3003 if (si->sn_prof_on)
3004 {
3005 ++si->sn_pr_count;
3006 profile_start(&si->sn_pr_start);
3007 profile_zero(&si->sn_pr_children);
3008 }
3009 }
3010# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011#endif
3012
Bram Moolenaar67435d92017-10-19 21:04:37 +02003013 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3014
3015 /* Read the first line so we can check for a UTF-8 BOM. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02003016 firstline = getsourceline(0, (void *)&cookie, 0, TRUE);
Bram Moolenaar67435d92017-10-19 21:04:37 +02003017 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3018 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3019 {
3020 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3021 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3022 p = string_convert(&cookie.conv, firstline + 3, NULL);
3023 if (p == NULL)
3024 p = vim_strsave(firstline + 3);
3025 if (p != NULL)
3026 {
3027 vim_free(firstline);
3028 firstline = p;
3029 }
3030 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02003031
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032 /*
3033 * Call do_cmdline, which will call getsourceline() to get the lines.
3034 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003035 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003038
3039#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003040 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003041 {
3042 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003043 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003044 if (si->sn_prof_on)
3045 {
3046 profile_end(&si->sn_pr_start);
3047 profile_sub_wait(&wait_start, &si->sn_pr_start);
3048 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003049 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3050 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003051 }
3052 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053#endif
3054
3055 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003056 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 sourcing_name = save_sourcing_name;
3058 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 if (p_verbose > 1)
3060 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003061 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003062 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003064 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003065 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 }
3067#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003068 if (time_fd != NULL)
3069 {
3070 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3071 time_msg((char *)IObuff, &tv_start);
3072 time_pop(&tv_rel);
3073 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074#endif
3075
Bram Moolenaar2b618522019-01-12 13:26:03 +01003076 if (!got_int)
3077 trigger_source_post = TRUE;
3078
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079#ifdef FEAT_EVAL
3080 /*
3081 * After a "finish" in debug mode, need to break at first command of next
3082 * sourced file.
3083 */
3084 if (save_debug_break_level > ex_nesting_level
3085 && debug_break_level == ex_nesting_level)
3086 ++debug_break_level;
3087#endif
3088
Bram Moolenaar05159a02005-02-26 23:04:13 +00003089#ifdef FEAT_EVAL
3090almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003091 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003092 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003093# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003094 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003095 prof_child_exit(&wait_start); /* leaving a child now */
3096# endif
3097#endif
3098 fclose(cookie.fp);
3099 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003100 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003101 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003102
Bram Moolenaar2b618522019-01-12 13:26:03 +01003103 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003104 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003105
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106theend:
3107 vim_free(fname_exp);
3108 return retval;
3109}
3110
3111#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003112
Bram Moolenaar071d4272004-06-13 20:20:40 +00003113/*
3114 * ":scriptnames"
3115 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003117ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118{
3119 int i;
3120
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003121 if (eap->addr_count > 0)
3122 {
3123 // :script {scriptId}: edit the script
3124 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003125 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003126 else
3127 {
3128 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3129 do_exedit(eap, NULL);
3130 }
3131 return;
3132 }
3133
Bram Moolenaar05159a02005-02-26 23:04:13 +00003134 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3135 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003136 {
3137 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3138 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003139 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003140 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141}
3142
3143# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3144/*
3145 * Fix slashes in the list of script names for 'shellslash'.
3146 */
3147 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003148scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149{
3150 int i;
3151
Bram Moolenaar05159a02005-02-26 23:04:13 +00003152 for (i = 1; i <= script_items.ga_len; ++i)
3153 if (SCRIPT_ITEM(i).sn_name != NULL)
3154 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155}
3156# endif
3157
3158/*
3159 * Get a pointer to a script name. Used for ":verbose set".
3160 */
3161 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003162get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163{
3164 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003165 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003166 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003167 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003169 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003171 return (char_u *)_("environment variable");
3172 if (id == SID_ERROR)
3173 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003174 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003176
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003177# if defined(EXITFREE) || defined(PROTO)
3178 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003179free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003180{
3181 int i;
3182
3183 for (i = script_items.ga_len; i > 0; --i)
3184 vim_free(SCRIPT_ITEM(i).sn_name);
3185 ga_clear(&script_items);
3186}
3187# endif
3188
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189#endif
3190
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003191 linenr_T
3192get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), void *cookie)
3193{
3194 return fgetline == getsourceline
3195 ? ((struct source_cookie *)cookie)->sourcing_lnum
3196 : sourcing_lnum;
3197}
3198
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199/*
3200 * Get one full line from a sourced file.
3201 * Called by do_cmdline() when it's called from do_source().
3202 *
3203 * Return a pointer to the line in allocated memory.
3204 * Return NULL for end-of-file or some error.
3205 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206 char_u *
Bram Moolenaare96a2492019-06-25 04:12:16 +02003207getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208{
3209 struct source_cookie *sp = (struct source_cookie *)cookie;
3210 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003211 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212
3213#ifdef FEAT_EVAL
3214 /* If breakpoints have been added/deleted need to check for it. */
3215 if (sp->dbg_tick < debug_tick)
3216 {
3217 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3218 sp->dbg_tick = debug_tick;
3219 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003220# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003221 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003222 script_line_end();
3223# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003225
3226 // Set the current sourcing line number.
3227 sourcing_lnum = sp->sourcing_lnum + 1;
3228
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229 /*
3230 * Get current line. If there is a read-ahead line, use it, otherwise get
3231 * one now.
3232 */
3233 if (sp->finished)
3234 line = NULL;
3235 else if (sp->nextline == NULL)
3236 line = get_one_sourceline(sp);
3237 else
3238 {
3239 line = sp->nextline;
3240 sp->nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003241 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003243#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003244 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003245 script_line_start();
3246#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247
3248 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3249 * contain the 'C' flag. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02003250 if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251 {
3252 /* compensate for the one line read-ahead */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003253 --sp->sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003254
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003255 // Get the next line and concatenate it when it starts with a
3256 // backslash. We always need to read the next line, keep it in
3257 // sp->nextline.
3258 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003259 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003260 if (sp->nextline != NULL
3261 && (*(p = skipwhite(sp->nextline)) == '\\'
3262 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003264 garray_T ga;
3265
Bram Moolenaarb549a732012-02-22 18:29:33 +01003266 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003267 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003268 if (*p == '\\')
3269 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003270 for (;;)
3271 {
3272 vim_free(sp->nextline);
3273 sp->nextline = get_one_sourceline(sp);
3274 if (sp->nextline == NULL)
3275 break;
3276 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003277 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003278 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003279 // Adjust the growsize to the current length to speed up
3280 // concatenating many lines.
3281 if (ga.ga_len > 400)
3282 {
3283 if (ga.ga_len > 8000)
3284 ga.ga_growsize = 8000;
3285 else
3286 ga.ga_growsize = ga.ga_len;
3287 }
3288 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003289 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003290 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3291 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003292 }
3293 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003295 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296 }
3297 }
3298
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3300 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003301 char_u *s;
3302
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 /* Convert the encoding of the script line. */
3304 s = string_convert(&sp->conv, line, NULL);
3305 if (s != NULL)
3306 {
3307 vim_free(line);
3308 line = s;
3309 }
3310 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003311
3312#ifdef FEAT_EVAL
3313 /* Did we encounter a breakpoint? */
3314 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3315 {
3316 dbg_breakpoint(sp->fname, sourcing_lnum);
3317 /* Find next breakpoint. */
3318 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3319 sp->dbg_tick = debug_tick;
3320 }
3321#endif
3322
3323 return line;
3324}
3325
3326 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003327get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328{
3329 garray_T ga;
3330 int len;
3331 int c;
3332 char_u *buf;
3333#ifdef USE_CRNL
3334 int has_cr; /* CR-LF found */
3335#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 int have_read = FALSE;
3337
3338 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003339 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340
3341 /*
3342 * Loop until there is a finished line (or end-of-file).
3343 */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003344 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 for (;;)
3346 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003347 /* make room to read at least 120 (more) characters */
3348 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 break;
3350 buf = (char_u *)ga.ga_data;
3351
Bram Moolenaar00590742019-02-15 21:06:09 +01003352 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003353 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003354 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003355 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356#ifdef USE_CRNL
3357 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3358 * CTRL-Z by its own, or after a NL. */
3359 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3360 && sp->fileformat == EOL_DOS
3361 && buf[len - 1] == Ctrl_Z)
3362 {
3363 buf[len - 1] = NUL;
3364 break;
3365 }
3366#endif
3367
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003369 ga.ga_len = len;
3370
3371 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003372 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 continue;
3374
3375 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3376 {
3377#ifdef USE_CRNL
3378 has_cr = (len >= 2 && buf[len - 2] == '\r');
3379 if (sp->fileformat == EOL_UNKNOWN)
3380 {
3381 if (has_cr)
3382 sp->fileformat = EOL_DOS;
3383 else
3384 sp->fileformat = EOL_UNIX;
3385 }
3386
3387 if (sp->fileformat == EOL_DOS)
3388 {
3389 if (has_cr) /* replace trailing CR */
3390 {
3391 buf[len - 2] = '\n';
3392 --len;
3393 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 }
3395 else /* lines like ":map xx yy^M" will have failed */
3396 {
3397 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003398 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003399 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003400 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003401 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 sp->error = TRUE;
3403 sp->fileformat = EOL_UNIX;
3404 }
3405 }
3406#endif
3407 /* The '\n' is escaped if there is an odd number of ^V's just
3408 * before it, first set "c" just before the 'V's and then check
3409 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3410 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3411 ;
3412 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3413 {
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003414 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003415 continue;
3416 }
3417
3418 buf[len - 1] = NUL; /* remove the NL */
3419 }
3420
3421 /*
3422 * Check for ^C here now and then, so recursive :so can be broken.
3423 */
3424 line_breakcheck();
3425 break;
3426 }
3427
3428 if (have_read)
3429 return (char_u *)ga.ga_data;
3430
3431 vim_free(ga.ga_data);
3432 return NULL;
3433}
3434
3435/*
3436 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003439ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441 struct source_cookie *sp;
3442 char_u *name;
3443
3444 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3445 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003446 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447 return;
3448 }
3449
3450 if (*eap->arg != NUL)
3451 {
3452 name = enc_canonize(eap->arg);
3453 if (name == NULL) /* out of memory */
3454 return;
3455 }
3456 else
3457 name = eap->arg;
3458
3459 /* Setup for conversion from the specified encoding to 'encoding'. */
3460 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3461 convert_setup(&sp->conv, name, p_enc);
3462
3463 if (name != eap->arg)
3464 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465}
3466
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003467/*
3468 * ":scriptversion": Set Vim script version for a sourced script.
3469 */
3470 void
3471ex_scriptversion(exarg_T *eap UNUSED)
3472{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02003473#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003474 int nr;
3475
3476 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3477 {
3478 emsg(_("E984: :scriptversion used outside of a sourced file"));
3479 return;
3480 }
3481
3482 nr = getdigits(&eap->arg);
3483 if (nr == 0 || *eap->arg != NUL)
3484 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02003485 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003486 semsg(_("E999: scriptversion not supported: %d"), nr);
3487 else
3488 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02003489#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003490}
3491
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492#if defined(FEAT_EVAL) || defined(PROTO)
3493/*
3494 * ":finish": Mark a sourced file as finished.
3495 */
3496 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003497ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498{
3499 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3500 do_finish(eap, FALSE);
3501 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003502 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503}
3504
3505/*
3506 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3507 * Also called for a pending finish at the ":endtry" or after returning from
3508 * an extra do_cmdline(). "reanimate" is used in the latter case.
3509 */
3510 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003511do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512{
3513 int idx;
3514
3515 if (reanimate)
3516 ((struct source_cookie *)getline_cookie(eap->getline,
3517 eap->cookie))->finished = FALSE;
3518
3519 /*
3520 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3521 * not in its finally clause (which then is to be executed next) is found.
3522 * In this case, make the ":finish" pending for execution at the ":endtry".
3523 * Otherwise, finish normally.
3524 */
3525 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3526 if (idx >= 0)
3527 {
3528 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3529 report_make_pending(CSTP_FINISH, NULL);
3530 }
3531 else
3532 ((struct source_cookie *)getline_cookie(eap->getline,
3533 eap->cookie))->finished = TRUE;
3534}
3535
3536
3537/*
3538 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3539 * message for missing ":endif".
3540 * Return FALSE when not sourcing a file.
3541 */
3542 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003543source_finished(
Bram Moolenaare96a2492019-06-25 04:12:16 +02003544 char_u *(*fgetline)(int, void *, int, int),
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003545 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003547 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003549 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003550}
3551#endif
3552
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553/*
3554 * ":checktime [buffer]"
3555 */
3556 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003557ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003558{
3559 buf_T *buf;
3560 int save_no_check_timestamps = no_check_timestamps;
3561
3562 no_check_timestamps = 0;
3563 if (eap->addr_count == 0) /* default is all buffers */
3564 check_timestamps(FALSE);
3565 else
3566 {
3567 buf = buflist_findnr((int)eap->line2);
3568 if (buf != NULL) /* cannot happen? */
3569 (void)buf_check_timestamp(buf, FALSE);
3570 }
3571 no_check_timestamps = save_no_check_timestamps;
3572}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573
Bram Moolenaar071d4272004-06-13 20:20:40 +00003574#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3575 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003576# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003577 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003578get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003579{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003580 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003582 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003583 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584
Bram Moolenaar4f974752019-02-17 17:44:42 +01003585# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 if (loc != NULL)
3587 {
3588 char_u *p;
3589
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003590 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3591 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592 p = vim_strchr(loc, '=');
3593 if (p != NULL)
3594 {
3595 loc = ++p;
3596 while (*p != NUL) /* remove trailing newline */
3597 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003598 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003599 {
3600 *p = NUL;
3601 break;
3602 }
3603 ++p;
3604 }
3605 }
3606 }
3607# endif
3608
3609 return loc;
3610}
3611#endif
3612
3613
Bram Moolenaar4f974752019-02-17 17:44:42 +01003614#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615/*
3616 * On MS-Windows locale names are strings like "German_Germany.1252", but
3617 * gettext expects "de". Try to translate one into another here for a few
3618 * supported languages.
3619 */
3620 static char_u *
3621gettext_lang(char_u *name)
3622{
3623 int i;
3624 static char *(mtable[]) = {
3625 "afrikaans", "af",
3626 "czech", "cs",
3627 "dutch", "nl",
3628 "german", "de",
3629 "english_united kingdom", "en_GB",
3630 "spanish", "es",
3631 "french", "fr",
3632 "italian", "it",
3633 "japanese", "ja",
3634 "korean", "ko",
3635 "norwegian", "no",
3636 "polish", "pl",
3637 "russian", "ru",
3638 "slovak", "sk",
3639 "swedish", "sv",
3640 "ukrainian", "uk",
3641 "chinese_china", "zh_CN",
3642 "chinese_taiwan", "zh_TW",
3643 NULL};
3644
3645 for (i = 0; mtable[i] != NULL; i += 2)
3646 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003647 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648 return name;
3649}
3650#endif
3651
3652#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3653/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01003654 * Return TRUE when "lang" starts with a valid language name.
3655 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
3656 */
3657 static int
3658is_valid_mess_lang(char_u *lang)
3659{
3660 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
3661}
3662
3663/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664 * Obtain the current messages language. Used to set the default for
3665 * 'helplang'. May return NULL or an empty string.
3666 */
3667 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003668get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669{
3670 char_u *p;
3671
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003672# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003674 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003675# else
3676 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003677 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3678 * and LC_MONETARY may be set differently for a Japanese working in the
3679 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003680 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681# endif
3682# else
3683 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003684 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685 {
3686 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003687 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003688 p = mch_getenv((char_u *)"LANG");
3689 }
3690# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003691# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692 p = gettext_lang(p);
3693# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01003694 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695}
3696#endif
3697
Bram Moolenaardef9e822004-12-31 20:58:58 +00003698/* Complicated #if; matches with where get_mess_env() is used below. */
3699#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3700 && defined(LC_MESSAGES))) \
3701 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00003702 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003703/*
3704 * Get the language used for messages from the environment.
3705 */
3706 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003707get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708{
3709 char_u *p;
3710
3711 p = mch_getenv((char_u *)"LC_ALL");
3712 if (p == NULL || *p == NUL)
3713 {
3714 p = mch_getenv((char_u *)"LC_MESSAGES");
3715 if (p == NULL || *p == NUL)
3716 {
3717 p = mch_getenv((char_u *)"LANG");
3718 if (p != NULL && VIM_ISDIGIT(*p))
3719 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003720# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003722 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723# endif
3724 }
3725 }
3726 return p;
3727}
3728#endif
3729
3730#if defined(FEAT_EVAL) || defined(PROTO)
3731
3732/*
3733 * Set the "v:lang" variable according to the current locale setting.
3734 * Also do "v:lc_time"and "v:ctype".
3735 */
3736 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003737set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738{
3739 char_u *loc;
3740
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003741# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003742 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743# else
3744 /* setlocale() not supported: use the default value */
3745 loc = (char_u *)"C";
3746# endif
3747 set_vim_var_string(VV_CTYPE, loc, -1);
3748
3749 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3750 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003751# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003752 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753# else
3754 loc = get_mess_env();
3755# endif
3756 set_vim_var_string(VV_LANG, loc, -1);
3757
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003758# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003759 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760# endif
3761 set_vim_var_string(VV_LC_TIME, loc, -1);
3762}
3763#endif
3764
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01003765#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00003766/*
3767 * ":language": Set the language (locale).
3768 */
3769 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003770ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771{
3772 char *loc;
3773 char_u *p;
3774 char_u *name;
3775 int what = LC_ALL;
3776 char *whatstr = "";
3777#ifdef LC_MESSAGES
3778# define VIM_LC_MESSAGES LC_MESSAGES
3779#else
3780# define VIM_LC_MESSAGES 6789
3781#endif
3782
3783 name = eap->arg;
3784
3785 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3786 * Allow abbreviation, but require at least 3 characters to avoid
3787 * confusion with a two letter language name "me" or "ct". */
3788 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003789 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790 {
3791 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3792 {
3793 what = VIM_LC_MESSAGES;
3794 name = skipwhite(p);
3795 whatstr = "messages ";
3796 }
3797 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3798 {
3799 what = LC_CTYPE;
3800 name = skipwhite(p);
3801 whatstr = "ctype ";
3802 }
3803 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3804 {
3805 what = LC_TIME;
3806 name = skipwhite(p);
3807 whatstr = "time ";
3808 }
3809 }
3810
3811 if (*name == NUL)
3812 {
3813#ifndef LC_MESSAGES
3814 if (what == VIM_LC_MESSAGES)
3815 p = get_mess_env();
3816 else
3817#endif
3818 p = (char_u *)setlocale(what, NULL);
3819 if (p == NULL || *p == NUL)
3820 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003821 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 }
3823 else
3824 {
3825#ifndef LC_MESSAGES
3826 if (what == VIM_LC_MESSAGES)
3827 loc = "";
3828 else
3829#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003830 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003832#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
3833 /* Make sure strtod() uses a decimal point, not a comma. */
3834 setlocale(LC_NUMERIC, "C");
3835#endif
3836 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003838 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 else
3840 {
3841#ifdef HAVE_NL_MSG_CAT_CNTR
3842 /* Need to do this for GNU gettext, otherwise cached translations
3843 * will be used again. */
3844 extern int _nl_msg_cat_cntr;
3845
3846 ++_nl_msg_cat_cntr;
3847#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00003848 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
3850
3851 if (what != LC_TIME)
3852 {
3853 /* Tell gettext() what to translate to. It apparently doesn't
3854 * use the currently effective locale. Also do this when
3855 * FEAT_GETTEXT isn't defined, so that shell commands use this
3856 * value. */
3857 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003858 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02003860
3861 /* Clear $LANGUAGE because GNU gettext uses it. */
3862 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01003863# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003864 /* Apparently MS-Windows printf() may cause a crash when
3865 * we give it 8-bit text while it's expecting text in the
3866 * current locale. This call avoids that. */
3867 setlocale(LC_CTYPE, "C");
3868# endif
3869 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870 if (what != LC_CTYPE)
3871 {
3872 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003873#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 mname = gettext_lang(name);
3875#else
3876 mname = name;
3877#endif
3878 vim_setenv((char_u *)"LC_MESSAGES", mname);
3879#ifdef FEAT_MULTI_LANG
3880 set_helplang_default(mname);
3881#endif
3882 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 }
3884
3885# ifdef FEAT_EVAL
3886 /* Set v:lang, v:lc_time and v:ctype to the final result. */
3887 set_lang_var();
3888# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02003889# ifdef FEAT_TITLE
3890 maketitle();
3891# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892 }
3893 }
3894}
3895
3896# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003897
3898static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003899
Bram Moolenaar4f974752019-02-17 17:44:42 +01003900# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003901static int did_init_locales = FALSE;
3902
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003903/* Return an array of strings for all available locales + NULL for the
3904 * last element. Return NULL in case of error. */
3905 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003906find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003907{
3908 garray_T locales_ga;
3909 char_u *loc;
3910
3911 /* Find all available locales by running command "locale -a". If this
3912 * doesn't work we won't have completion. */
3913 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02003914 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003915 if (locale_a == NULL)
3916 return NULL;
3917 ga_init2(&locales_ga, sizeof(char_u *), 20);
3918
3919 /* Transform locale_a string where each locale is separated by "\n"
3920 * into an array of locale strings. */
3921 loc = (char_u *)strtok((char *)locale_a, "\n");
3922
3923 while (loc != NULL)
3924 {
3925 if (ga_grow(&locales_ga, 1) == FAIL)
3926 break;
3927 loc = vim_strsave(loc);
3928 if (loc == NULL)
3929 break;
3930
3931 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
3932 loc = (char_u *)strtok(NULL, "\n");
3933 }
3934 vim_free(locale_a);
3935 if (ga_grow(&locales_ga, 1) == FAIL)
3936 {
3937 ga_clear(&locales_ga);
3938 return NULL;
3939 }
3940 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
3941 return (char_u **)locales_ga.ga_data;
3942}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003943# endif
3944
3945/*
3946 * Lazy initialization of all available locales.
3947 */
3948 static void
3949init_locales(void)
3950{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003951# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003952 if (!did_init_locales)
3953 {
3954 did_init_locales = TRUE;
3955 locales = find_locales();
3956 }
3957# endif
3958}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003959
3960# if defined(EXITFREE) || defined(PROTO)
3961 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003962free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003963{
3964 int i;
3965 if (locales != NULL)
3966 {
3967 for (i = 0; locales[i] != NULL; i++)
3968 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01003969 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003970 }
3971}
3972# endif
3973
Bram Moolenaar071d4272004-06-13 20:20:40 +00003974/*
3975 * Function given to ExpandGeneric() to obtain the possible arguments of the
3976 * ":language" command.
3977 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003979get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980{
3981 if (idx == 0)
3982 return (char_u *)"messages";
3983 if (idx == 1)
3984 return (char_u *)"ctype";
3985 if (idx == 2)
3986 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003987
3988 init_locales();
3989 if (locales == NULL)
3990 return NULL;
3991 return locales[idx - 3];
3992}
3993
3994/*
3995 * Function given to ExpandGeneric() to obtain the available locales.
3996 */
3997 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003998get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003999{
4000 init_locales();
4001 if (locales == NULL)
4002 return NULL;
4003 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004}
4005# endif
4006
4007#endif