blob: a275fb8b70734f8706f25c7eab085095c9f25b2b [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 Moolenaardcaf10e2005-01-21 11:55:25 +00001450 /* Don't do syntax HL autocommands. Skipping the syntax file is a
1451 * great speed improvement. */
1452 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001454#ifdef FEAT_CLIPBOARD
1455 start_global_changes();
1456#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457
1458 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001459 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02001460 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001461 || !check_changed(curbuf, CCGD_AW
1462 | (eap->forceit ? CCGD_FORCEIT : 0)
1463 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001464 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001466 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001467 wp = firstwin;
1468 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001469 switch (eap->cmdidx)
1470 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01001471 case CMD_windo:
1472 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
1473 i++;
1474 break;
1475 case CMD_tabdo:
1476 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
1477 i++;
1478 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001479 case CMD_argdo:
1480 i = eap->line1 - 1;
1481 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001482 default:
1483 break;
1484 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485 /* set pcmark now */
1486 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001487 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01001488 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001489 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01001490 || !buf->b_p_bl); buf = buf->b_next)
1491 if (buf->b_fnum > eap->line2)
1492 {
1493 buf = NULL;
1494 break;
1495 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001496 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01001497 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001498 }
1499#ifdef FEAT_QUICKFIX
1500 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1501 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1502 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02001503 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001504 if (qf_size <= 0 || eap->line1 > qf_size)
1505 buf = NULL;
1506 else
1507 {
1508 ex_cc(eap);
1509
1510 buf = curbuf;
1511 i = eap->line1 - 1;
1512 if (eap->addr_count <= 0)
1513 /* default is all the quickfix/location list entries */
1514 eap->line2 = qf_size;
1515 }
1516 }
1517#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001518 else
1519 setpcmark();
1520 listcmd_busy = TRUE; /* avoids setting pcmark below */
1521
Bram Moolenaare25bb902015-02-27 20:33:37 +01001522 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001523 {
1524 if (eap->cmdidx == CMD_argdo)
1525 {
1526 /* go to argument "i" */
1527 if (i == ARGCOUNT)
1528 break;
1529 /* Don't call do_argfile() when already there, it will try
1530 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001531 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001532 {
1533 /* Clear 'shm' to avoid that the file message overwrites
1534 * any output from the command. */
1535 p_shm_save = vim_strsave(p_shm);
1536 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001538 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1539 vim_free(p_shm_save);
1540 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 if (curwin->w_arg_idx != i)
1542 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001543 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001544 else if (eap->cmdidx == CMD_windo)
1545 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001546 /* go to window "wp" */
1547 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001549 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00001550 if (curwin != wp)
1551 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001552 wp = curwin->w_next;
1553 }
1554 else if (eap->cmdidx == CMD_tabdo)
1555 {
1556 /* go to window "tp" */
1557 if (!valid_tabpage(tp))
1558 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02001559 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001560 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001562 else if (eap->cmdidx == CMD_bufdo)
1563 {
1564 /* Remember the number of the next listed buffer, in case
1565 * ":bwipe" is used or autocommands do something strange. */
1566 next_fnum = -1;
1567 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
1568 if (buf->b_p_bl)
1569 {
1570 next_fnum = buf->b_fnum;
1571 break;
1572 }
1573 }
1574
Bram Moolenaara162bc52015-01-07 16:54:21 +01001575 ++i;
1576
Bram Moolenaar071d4272004-06-13 20:20:40 +00001577 /* execute the command */
1578 do_cmdline(eap->arg, eap->getline, eap->cookie,
1579 DOCMD_VERBOSE + DOCMD_NOWAIT);
1580
1581 if (eap->cmdidx == CMD_bufdo)
1582 {
1583 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01001584 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001585 break;
1586 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001587 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588 if (buf->b_fnum == next_fnum)
1589 break;
1590 if (buf == NULL)
1591 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001592
1593 /* Go to the next buffer. Clear 'shm' to avoid that the file
1594 * message overwrites any output from the command. */
1595 p_shm_save = vim_strsave(p_shm);
1596 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001598 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1599 vim_free(p_shm_save);
1600
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001601 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 if (curbuf->b_fnum != next_fnum)
1603 break;
1604 }
1605
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001606#ifdef FEAT_QUICKFIX
1607 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1608 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1609 {
1610 if (i >= qf_size || i >= eap->line2)
1611 break;
1612
1613 qf_idx = qf_get_cur_idx(eap);
1614
1615 ex_cnext(eap);
1616
1617 /* If jumping to the next quickfix entry fails, quit here */
1618 if (qf_get_cur_idx(eap) == qf_idx)
1619 break;
1620 }
1621#endif
1622
Bram Moolenaar071d4272004-06-13 20:20:40 +00001623 if (eap->cmdidx == CMD_windo)
1624 {
1625 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01001626
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627 /* required when 'scrollbind' has been set */
1628 if (curwin->w_p_scb)
1629 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01001631
Bram Moolenaara162bc52015-01-07 16:54:21 +01001632 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
1633 if (i+1 > eap->line2)
1634 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001635 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
1636 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001637 }
1638 listcmd_busy = FALSE;
1639 }
1640
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001641#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001642 if (save_ei != NULL)
1643 {
1644 au_event_restore(save_ei);
1645 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
1646 curbuf->b_fname, TRUE, curbuf);
1647 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001649#ifdef FEAT_CLIPBOARD
1650 end_global_changes();
1651#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001652}
1653
1654/*
1655 * Add files[count] to the arglist of the current window after arg "after".
1656 * The file names in files[count] must have been allocated and are taken over.
1657 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001659 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001660alist_add_list(
1661 int count,
1662 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001663 int after, // where to add: 0 = before first one
1664 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665{
1666 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01001667 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001668
1669 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
1670 {
1671 if (after < 0)
1672 after = 0;
1673 if (after > ARGCOUNT)
1674 after = ARGCOUNT;
1675 if (after < ARGCOUNT)
1676 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
1677 (ARGCOUNT - after) * sizeof(aentry_T));
1678 for (i = 0; i < count; ++i)
1679 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001680 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
1681
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001683 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 }
1685 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01001686 if (old_argcount > 0 && curwin->w_arg_idx >= after)
1687 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001688 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689 }
1690
1691 for (i = 0; i < count; ++i)
1692 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693}
1694
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02001695#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1696/*
1697 * Function given to ExpandGeneric() to obtain the possible arguments of the
1698 * argedit and argdelete commands.
1699 */
1700 char_u *
1701get_arglist_name(expand_T *xp UNUSED, int idx)
1702{
1703 if (idx >= ARGCOUNT)
1704 return NULL;
1705
1706 return alist_name(&ARGLIST[idx]);
1707}
1708#endif
1709
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001710
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711#ifdef FEAT_EVAL
1712/*
1713 * ":compiler[!] {name}"
1714 */
1715 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001716ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717{
1718 char_u *buf;
1719 char_u *old_cur_comp = NULL;
1720 char_u *p;
1721
1722 if (*eap->arg == NUL)
1723 {
1724 /* List all compiler scripts. */
1725 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1726 /* ) keep the indenter happy... */
1727 }
1728 else
1729 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02001730 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731 if (buf != NULL)
1732 {
1733 if (eap->forceit)
1734 {
1735 /* ":compiler! {name}" sets global options */
1736 do_cmdline_cmd((char_u *)
1737 "command -nargs=* CompilerSet set <args>");
1738 }
1739 else
1740 {
1741 /* ":compiler! {name}" sets local options.
1742 * To remain backwards compatible "current_compiler" is always
1743 * used. A user's compiler plugin may set it, the distributed
1744 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001745 * "b:current_compiler" and restore "current_compiler".
1746 * Explicitly prepend "g:" to make it work in a function. */
1747 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748 if (old_cur_comp != NULL)
1749 old_cur_comp = vim_strsave(old_cur_comp);
1750 do_cmdline_cmd((char_u *)
1751 "command -nargs=* CompilerSet setlocal <args>");
1752 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001753 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00001754 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755
1756 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001757 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001758 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 vim_free(buf);
1760
1761 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1762
1763 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001764 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 if (p != NULL)
1766 set_internal_string_var((char_u *)"b:current_compiler", p);
1767
1768 /* Restore "current_compiler" for ":compiler {name}". */
1769 if (!eap->forceit)
1770 {
1771 if (old_cur_comp != NULL)
1772 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001773 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774 old_cur_comp);
1775 vim_free(old_cur_comp);
1776 }
1777 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001778 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779 }
1780 }
1781 }
1782}
1783#endif
1784
1785/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001786 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001787 */
1788 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001789ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001790{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001791 char_u *arg = eap->arg;
1792 char_u *p = skiptowhite(arg);
1793 int len = (int)(p - arg);
1794 int flags = eap->forceit ? DIP_ALL : 0;
1795
1796 if (STRNCMP(arg, "START", len) == 0)
1797 {
1798 flags += DIP_START + DIP_NORTP;
1799 arg = skipwhite(arg + len);
1800 }
1801 else if (STRNCMP(arg, "OPT", len) == 0)
1802 {
1803 flags += DIP_OPT + DIP_NORTP;
1804 arg = skipwhite(arg + len);
1805 }
1806 else if (STRNCMP(arg, "PACK", len) == 0)
1807 {
1808 flags += DIP_START + DIP_OPT + DIP_NORTP;
1809 arg = skipwhite(arg + len);
1810 }
1811 else if (STRNCMP(arg, "ALL", len) == 0)
1812 {
1813 flags += DIP_START + DIP_OPT;
1814 arg = skipwhite(arg + len);
1815 }
1816
1817 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818}
1819
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001821source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001823 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824}
1825
1826/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001827 * Find the file "name" in all directories in "path" and invoke
1828 * "callback(fname, cookie)".
1829 * "name" can contain wildcards.
1830 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
1831 * When "flags" has DIP_DIR: find directories instead of files.
1832 * When "flags" has DIP_ERR: give an error message if there is no match.
1833 *
1834 * return FAIL when no file could be sourced, OK otherwise.
1835 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01001836 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001837do_in_path(
1838 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001839 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01001840 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001841 void (*callback)(char_u *fname, void *ck),
1842 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843{
1844 char_u *rtp;
1845 char_u *np;
1846 char_u *buf;
1847 char_u *rtp_copy;
1848 char_u *tail;
1849 int num_files;
1850 char_u **files;
1851 int i;
1852 int did_one = FALSE;
1853#ifdef AMIGA
1854 struct Process *proc = (struct Process *)FindTask(0L);
1855 APTR save_winptr = proc->pr_WindowPtr;
1856
1857 /* Avoid a requester here for a volume that doesn't exist. */
1858 proc->pr_WindowPtr = (APTR)-1L;
1859#endif
1860
1861 /* Make a copy of 'runtimepath'. Invoking the callback may change the
1862 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001863 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 buf = alloc(MAXPATHL);
1865 if (buf != NULL && rtp_copy != NULL)
1866 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001867 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001868 {
1869 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001870 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001871 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001872 verbose_leave();
1873 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001874
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 /* Loop over all entries in 'runtimepath'. */
1876 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01001877 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02001879 size_t buflen;
1880
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881 /* Copy the path from 'runtimepath' to buf[]. */
1882 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02001883 buflen = STRLEN(buf);
1884
1885 /* Skip after or non-after directories. */
1886 if (flags & (DIP_NOAFTER | DIP_AFTER))
1887 {
1888 int is_after = buflen >= 5
1889 && STRCMP(buf + buflen - 5, "after") == 0;
1890
1891 if ((is_after && (flags & DIP_NOAFTER))
1892 || (!is_after && (flags & DIP_AFTER)))
1893 continue;
1894 }
1895
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001896 if (name == NULL)
1897 {
1898 (*callback)(buf, (void *) &cookie);
1899 if (!did_one)
1900 did_one = (cookie == NULL);
1901 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02001902 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 {
1904 add_pathsep(buf);
1905 tail = buf + STRLEN(buf);
1906
1907 /* Loop over all patterns in "name" */
1908 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01001909 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 {
1911 /* Append the pattern from "name" to buf[]. */
1912 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
1913 "\t ");
1914
1915 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001916 {
1917 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001918 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001919 verbose_leave();
1920 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921
1922 /* Expand wildcards, invoke the callback for each match. */
1923 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01001924 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 {
1926 for (i = 0; i < num_files; ++i)
1927 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001928 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01001930 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 break;
1932 }
1933 FreeWild(num_files, files);
1934 }
1935 }
1936 }
1937 }
1938 }
1939 vim_free(buf);
1940 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001941 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001942 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001943 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
1944
1945 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001946 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001947 else if (p_verbose > 0)
1948 {
1949 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001950 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001951 verbose_leave();
1952 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001953 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001954
1955#ifdef AMIGA
1956 proc->pr_WindowPtr = save_winptr;
1957#endif
1958
1959 return did_one ? OK : FAIL;
1960}
1961
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001962/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001963 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001964 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001965 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
1966 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001967 * Returns OK when at least one match found, FAIL otherwise.
1968 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001969 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001970 * passed by reference in this case, setting it to NULL indicates that callback
1971 * has done its job.
1972 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001973 static int
1974do_in_path_and_pp(
1975 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001976 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001977 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001978 void (*callback)(char_u *fname, void *ck),
1979 void *cookie)
1980{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001981 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001982 char_u *s;
1983 int len;
1984 char *start_dir = "pack/*/start/*/%s";
1985 char *opt_dir = "pack/*/opt/*/%s";
1986
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001987 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001988 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001989
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001990 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001991 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01001992 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001993 s = alloc(len);
1994 if (s == NULL)
1995 return FAIL;
1996 vim_snprintf((char *)s, len, start_dir, name);
1997 done = do_in_path(p_pp, s, flags, callback, cookie);
1998 vim_free(s);
1999 }
2000
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002001 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002002 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002003 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002004 s = alloc(len);
2005 if (s == NULL)
2006 return FAIL;
2007 vim_snprintf((char *)s, len, opt_dir, name);
2008 done = do_in_path(p_pp, s, flags, callback, cookie);
2009 vim_free(s);
2010 }
2011
2012 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002013}
2014
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002015/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002016 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2017 */
2018 int
2019do_in_runtimepath(
2020 char_u *name,
2021 int flags,
2022 void (*callback)(char_u *fname, void *ck),
2023 void *cookie)
2024{
2025 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2026}
2027
2028/*
2029 * Source the file "name" from all directories in 'runtimepath'.
2030 * "name" can contain wildcards.
2031 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2032 *
2033 * return FAIL when no file could be sourced, OK otherwise.
2034 */
2035 int
2036source_runtime(char_u *name, int flags)
2037{
2038 return source_in_path(p_rtp, name, flags);
2039}
2040
2041/*
2042 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2043 */
2044 int
2045source_in_path(char_u *path, char_u *name, int flags)
2046{
2047 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2048}
2049
2050
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002051#if defined(FEAT_EVAL) || defined(PROTO)
2052
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002053/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002054 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002055 */
2056 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002057source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002058{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002059 int num_files;
2060 char_u **files;
2061 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002062
Bram Moolenaarf3654822016-03-04 22:12:23 +01002063 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002064 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002065 for (i = 0; i < num_files; ++i)
2066 (void)do_source(files[i], FALSE, DOSO_NONE);
2067 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002068 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002069}
2070
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002071/*
2072 * Add the package directory to 'runtimepath'.
2073 */
2074 static int
2075add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002076{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002077 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002078 char_u *entry;
2079 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002080 int c;
2081 char_u *new_rtp;
2082 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002083 size_t oldlen;
2084 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002085 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002086 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002087 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002088 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002089 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002090 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002091 char_u *buf = NULL;
2092 char_u *rtp_ffname;
2093 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002094 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002095
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002096 p4 = p3 = p2 = p1 = get_past_head(fname);
2097 for (p = p1; *p; MB_PTR_ADV(p))
2098 if (vim_ispathsep_nocolon(*p))
2099 {
2100 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2101 }
2102
2103 /* now we have:
2104 * rtp/pack/name/start/name
2105 * p4 p3 p2 p1
2106 *
2107 * find the part up to "pack" in 'runtimepath' */
2108 c = *++p4; /* append pathsep in order to expand symlink */
2109 *p4 = NUL;
2110 ffname = fix_fname(fname);
2111 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002112 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002113 return FAIL;
2114
Bram Moolenaar99396d42018-09-08 18:21:16 +02002115 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2116 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002117 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002118 buf = alloc(MAXPATHL);
2119 if (buf == NULL)
2120 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002121 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002122 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002123 char_u *cur_entry = entry;
2124
2125 copy_option_part(&entry, buf, MAXPATHL, ",");
2126 if (insp == NULL)
2127 {
2128 add_pathsep(buf);
2129 rtp_ffname = fix_fname(buf);
2130 if (rtp_ffname == NULL)
2131 goto theend;
2132 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2133 vim_free(rtp_ffname);
2134 if (match)
2135 // Insert "ffname" after this entry (and comma).
2136 insp = entry;
2137 }
2138
2139 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2140 && p > buf
2141 && vim_ispathsep(p[-1])
2142 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2143 {
2144 if (insp == NULL)
2145 // Did not find "ffname" before the first "after" directory,
2146 // insert it before this entry.
2147 insp = cur_entry;
2148 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002149 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002150 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002151 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002152
Bram Moolenaar99396d42018-09-08 18:21:16 +02002153 if (insp == NULL)
2154 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002155 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002156
Bram Moolenaar99396d42018-09-08 18:21:16 +02002157 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002158 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2159 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002160 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002161
2162 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002163 addlen = STRLEN(fname) + 1; // add one for comma
Bram Moolenaar51e14382019-05-25 20:21:28 +02002164 new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002165 if (new_rtp == NULL)
2166 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002167
2168 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2169 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002170 keep = (int)(insp - p_rtp);
2171 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002172 new_rtp_len = keep;
2173 if (*insp == NUL)
2174 new_rtp[new_rtp_len++] = ','; // add comma before
2175 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2176 new_rtp_len += addlen - 1;
2177 if (*insp != NUL)
2178 new_rtp[new_rtp_len++] = ','; // add comma after
2179
2180 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002181 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002182 int keep_after = (int)(after_insp - p_rtp);
2183
2184 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2185 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2186 keep_after - keep);
2187 new_rtp_len += keep_after - keep;
2188 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2189 new_rtp_len += afterlen - 1;
2190 new_rtp[new_rtp_len++] = ',';
2191 keep = keep_after;
2192 }
2193
2194 if (p_rtp[keep] != NUL)
2195 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2196 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2197 else
2198 new_rtp[new_rtp_len] = NUL;
2199
2200 if (afterlen > 0 && after_insp == NULL)
2201 {
2202 // Append afterdir when "after" was not found:
2203 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002204 STRCAT(new_rtp, ",");
2205 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002206 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002207
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002208 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2209 vim_free(new_rtp);
2210 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002211
2212theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002213 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002214 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002215 vim_free(afterdir);
2216 return retval;
2217}
2218
2219/*
2220 * Load scripts in "plugin" and "ftdetect" directories of the package.
2221 */
2222 static int
2223load_pack_plugin(char_u *fname)
2224{
2225 static char *plugpat = "%s/plugin/**/*.vim";
2226 static char *ftpat = "%s/ftdetect/*.vim";
2227 int len;
2228 char_u *ffname = fix_fname(fname);
2229 char_u *pat = NULL;
2230 int retval = FAIL;
2231
2232 if (ffname == NULL)
2233 return FAIL;
2234 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2235 pat = alloc(len);
2236 if (pat == NULL)
2237 goto theend;
2238 vim_snprintf((char *)pat, len, plugpat, ffname);
2239 source_all_matches(pat);
2240
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002241 {
2242 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2243
2244 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2245 * found when it loads. */
2246 if (cmd != NULL && eval_to_number(cmd) > 0)
2247 {
2248 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2249 vim_snprintf((char *)pat, len, ftpat, ffname);
2250 source_all_matches(pat);
2251 do_cmdline_cmd((char_u *)"augroup END");
2252 }
2253 vim_free(cmd);
2254 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002255 vim_free(pat);
2256 retval = OK;
2257
2258theend:
2259 vim_free(ffname);
2260 return retval;
2261}
2262
2263/* used for "cookie" of add_pack_plugin() */
2264static int APP_ADD_DIR;
2265static int APP_LOAD;
2266static int APP_BOTH;
2267
2268 static void
2269add_pack_plugin(char_u *fname, void *cookie)
2270{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002271 if (cookie != &APP_LOAD)
2272 {
2273 char_u *buf = alloc(MAXPATHL);
2274 char_u *p;
2275 int found = FALSE;
2276
2277 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002278 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002279 p = p_rtp;
2280 while (*p != NUL)
2281 {
2282 copy_option_part(&p, buf, MAXPATHL, ",");
2283 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2284 {
2285 found = TRUE;
2286 break;
2287 }
2288 }
2289 vim_free(buf);
2290 if (!found)
2291 /* directory is not yet in 'runtimepath', add it */
2292 if (add_pack_dir_to_rtp(fname) == FAIL)
2293 return;
2294 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002295
2296 if (cookie != &APP_ADD_DIR)
2297 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002298}
2299
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002300/*
2301 * Add all packages in the "start" directory to 'runtimepath'.
2302 */
2303 void
2304add_pack_start_dirs(void)
2305{
2306 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2307 add_pack_plugin, &APP_ADD_DIR);
2308}
2309
2310/*
2311 * Load plugins from all packages in the "start" directory.
2312 */
2313 void
2314load_start_packages(void)
2315{
2316 did_source_packages = TRUE;
2317 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2318 add_pack_plugin, &APP_LOAD);
2319}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002320
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002321/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002322 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002323 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002324 */
2325 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002326ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002327{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002328 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002329 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002330 /* First do a round to add all directories to 'runtimepath', then load
2331 * the plugins. This allows for plugins to use an autoload directory
2332 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002333 add_pack_start_dirs();
2334 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002335 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002336}
2337
2338/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002339 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002340 */
2341 void
2342ex_packadd(exarg_T *eap)
2343{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002344 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002345 int len;
2346 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002347 int round;
2348 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002349
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002350 /* Round 1: use "start", round 2: use "opt". */
2351 for (round = 1; round <= 2; ++round)
2352 {
2353 /* Only look under "start" when loading packages wasn't done yet. */
2354 if (round == 1 && did_source_packages)
2355 continue;
2356
2357 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002358 pat = alloc(len);
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002359 if (pat == NULL)
2360 return;
2361 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
2362 /* The first round don't give a "not found" error, in the second round
2363 * only when nothing was found in the first round. */
2364 res = do_in_path(p_pp, (char_u *)pat,
2365 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
2366 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
2367 vim_free(pat);
2368 }
Bram Moolenaar91715872016-03-03 17:13:03 +01002369}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002370#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01002371
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002372#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373/*
2374 * ":options"
2375 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002377ex_options(
2378 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379{
Bram Moolenaare0b59492019-05-21 20:54:45 +02002380 vim_setenv((char_u *)"OPTWIN_CMD",
2381 (char_u *)(cmdmod.tab ? "tab"
2382 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2384}
2385#endif
2386
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002387#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
2388
2389# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
2390/*
2391 * Detect Python 3 or 2, and initialize 'pyxversion'.
2392 */
2393 void
2394init_pyxversion(void)
2395{
2396 if (p_pyx == 0)
2397 {
2398 if (python3_enabled(FALSE))
2399 p_pyx = 3;
2400 else if (python_enabled(FALSE))
2401 p_pyx = 2;
2402 }
2403}
2404# endif
2405
2406/*
2407 * Does a file contain one of the following strings at the beginning of any
2408 * line?
2409 * "#!(any string)python2" => returns 2
2410 * "#!(any string)python3" => returns 3
2411 * "# requires python 2.x" => returns 2
2412 * "# requires python 3.x" => returns 3
2413 * otherwise return 0.
2414 */
2415 static int
2416requires_py_version(char_u *filename)
2417{
2418 FILE *file;
2419 int requires_py_version = 0;
2420 int i, lines;
2421
2422 lines = (int)p_mls;
2423 if (lines < 0)
2424 lines = 5;
2425
2426 file = mch_fopen((char *)filename, "r");
2427 if (file != NULL)
2428 {
2429 for (i = 0; i < lines; i++)
2430 {
2431 if (vim_fgets(IObuff, IOSIZE, file))
2432 break;
2433 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
2434 {
2435 /* Check shebang. */
2436 if (strstr((char *)IObuff + 2, "python2") != NULL)
2437 {
2438 requires_py_version = 2;
2439 break;
2440 }
2441 if (strstr((char *)IObuff + 2, "python3") != NULL)
2442 {
2443 requires_py_version = 3;
2444 break;
2445 }
2446 }
2447 IObuff[21] = '\0';
2448 if (STRCMP("# requires python 2.x", IObuff) == 0)
2449 {
2450 requires_py_version = 2;
2451 break;
2452 }
2453 if (STRCMP("# requires python 3.x", IObuff) == 0)
2454 {
2455 requires_py_version = 3;
2456 break;
2457 }
2458 }
2459 fclose(file);
2460 }
2461 return requires_py_version;
2462}
2463
2464
2465/*
2466 * Source a python file using the requested python version.
2467 */
2468 static void
2469source_pyx_file(exarg_T *eap, char_u *fname)
2470{
2471 exarg_T ex;
2472 int v = requires_py_version(fname);
2473
2474# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2475 init_pyxversion();
2476# endif
2477 if (v == 0)
2478 {
2479# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2480 /* user didn't choose a preference, 'pyx' is used */
2481 v = p_pyx;
2482# elif defined(FEAT_PYTHON)
2483 v = 2;
2484# elif defined(FEAT_PYTHON3)
2485 v = 3;
2486# endif
2487 }
2488
2489 /*
2490 * now source, if required python version is not supported show
2491 * unobtrusive message.
2492 */
2493 if (eap == NULL)
2494 vim_memset(&ex, 0, sizeof(ex));
2495 else
2496 ex = *eap;
2497 ex.arg = fname;
2498 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
2499
2500 if (v == 2)
2501 {
2502# ifdef FEAT_PYTHON
2503 ex_pyfile(&ex);
2504# else
2505 vim_snprintf((char *)IObuff, IOSIZE,
2506 _("W20: Required python version 2.x not supported, ignoring file: %s"),
2507 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002508 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002509# endif
2510 return;
2511 }
2512 else
2513 {
2514# ifdef FEAT_PYTHON3
2515 ex_py3file(&ex);
2516# else
2517 vim_snprintf((char *)IObuff, IOSIZE,
2518 _("W21: Required python version 3.x not supported, ignoring file: %s"),
2519 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002520 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002521# endif
2522 return;
2523 }
2524}
2525
2526/*
2527 * ":pyxfile {fname}"
2528 */
2529 void
2530ex_pyxfile(exarg_T *eap)
2531{
2532 source_pyx_file(eap, eap->arg);
2533}
2534
2535/*
2536 * ":pyx"
2537 */
2538 void
2539ex_pyx(exarg_T *eap)
2540{
2541# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2542 init_pyxversion();
2543 if (p_pyx == 2)
2544 ex_python(eap);
2545 else
2546 ex_py3(eap);
2547# elif defined(FEAT_PYTHON)
2548 ex_python(eap);
2549# elif defined(FEAT_PYTHON3)
2550 ex_py3(eap);
2551# endif
2552}
2553
2554/*
2555 * ":pyxdo"
2556 */
2557 void
2558ex_pyxdo(exarg_T *eap)
2559{
2560# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2561 init_pyxversion();
2562 if (p_pyx == 2)
2563 ex_pydo(eap);
2564 else
2565 ex_py3do(eap);
2566# elif defined(FEAT_PYTHON)
2567 ex_pydo(eap);
2568# elif defined(FEAT_PYTHON3)
2569 ex_py3do(eap);
2570# endif
2571}
2572
2573#endif
2574
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575/*
2576 * ":source {fname}"
2577 */
2578 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002579ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580{
2581#ifdef FEAT_BROWSE
2582 if (cmdmod.browse)
2583 {
2584 char_u *fname = NULL;
2585
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002586 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02002587 NULL, NULL,
2588 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 if (fname != NULL)
2590 {
2591 cmd_source(fname, eap);
2592 vim_free(fname);
2593 }
2594 }
2595 else
2596#endif
2597 cmd_source(eap->arg, eap);
2598}
2599
2600 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002601cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602{
2603 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002604 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002607 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002608 * Need to execute the commands directly. This is required at least
2609 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 * - ":g" command busy
2611 * - after ":argdo", ":windo" or ":bufdo"
2612 * - another command follows
2613 * - inside a loop
2614 */
2615 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2616#ifdef FEAT_EVAL
2617 || eap->cstack->cs_idx >= 0
2618#endif
2619 );
2620
2621 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002622 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002623 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624}
2625
2626/*
2627 * ":source" and associated commands.
2628 */
2629/*
2630 * Structure used to store info for each sourced file.
2631 * It is shared between do_source() and getsourceline().
2632 * This is required, because it needs to be handed to do_cmdline() and
2633 * sourcing can be done recursively.
2634 */
2635struct source_cookie
2636{
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002637 FILE *fp; // opened file for sourcing
2638 char_u *nextline; // if not NULL: line that was read ahead
2639 linenr_T sourcing_lnum; // line number of the source file
2640 int finished; // ":finish" used
Bram Moolenaar00590742019-02-15 21:06:09 +01002641#ifdef USE_CRNL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002642 int fileformat; // EOL_UNKNOWN, EOL_UNIX or EOL_DOS
2643 int error; // TRUE if LF found after CR-LF
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644#endif
2645#ifdef FEAT_EVAL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002646 linenr_T breakpoint; // next line with breakpoint or zero
2647 char_u *fname; // name of sourced file
2648 int dbg_tick; // debug_tick when breakpoint was set
2649 int level; // top nesting level of sourced file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002651 vimconv_T conv; // type of conversion
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652};
2653
2654#ifdef FEAT_EVAL
2655/*
2656 * Return the address holding the next breakpoint line for a source cookie.
2657 */
2658 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002659source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660{
2661 return &((struct source_cookie *)cookie)->breakpoint;
2662}
2663
2664/*
2665 * Return the address holding the debug tick for a source cookie.
2666 */
2667 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002668source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669{
2670 return &((struct source_cookie *)cookie)->dbg_tick;
2671}
2672
2673/*
2674 * Return the nesting level for a source cookie.
2675 */
2676 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002677source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678{
2679 return ((struct source_cookie *)cookie)->level;
2680}
2681#endif
2682
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002683static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684
Bram Moolenaar4f974752019-02-17 17:44:42 +01002685#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002686# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687/*
2688 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002689 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 */
2691 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002692fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693{
Bram Moolenaar4f974752019-02-17 17:44:42 +01002694# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002695 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2696# else
2697 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002698# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002699
2700 if (fd_tmp == -1)
2701 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002702
2703# ifdef HAVE_FD_CLOEXEC
2704 {
2705 int fdflags = fcntl(fd_tmp, F_GETFD);
2706 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02002707 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002708 }
2709# endif
2710
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 return fdopen(fd_tmp, READBIN);
2712}
2713#endif
2714
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715/*
2716 * do_source: Read the file "fname" and execute its lines as EX commands.
2717 *
2718 * This function may be called recursively!
2719 *
2720 * return FAIL if file could not be opened, OK otherwise
2721 */
2722 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002723do_source(
2724 char_u *fname,
2725 int check_other, /* check for .vimrc and _vimrc */
2726 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727{
2728 struct source_cookie cookie;
2729 char_u *save_sourcing_name;
2730 linenr_T save_sourcing_lnum;
2731 char_u *p;
2732 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002733 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734 int retval = FAIL;
2735#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002736 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002738 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002739 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002741 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02002743 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744 int stat_ok;
2745# endif
2746#endif
2747#ifdef STARTUPTIME
2748 struct timeval tv_rel;
2749 struct timeval tv_start;
2750#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002751#ifdef FEAT_PROFILE
2752 proftime_T wait_start;
2753#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002754 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757 if (p == NULL)
2758 return retval;
2759 fname_exp = fix_fname(p);
2760 vim_free(p);
2761 if (fname_exp == NULL)
2762 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763 if (mch_isdir(fname_exp))
2764 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002765 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 goto theend;
2767 }
2768
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002769 /* Apply SourceCmd autocommands, they should get the file and source it. */
2770 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2771 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2772 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002773 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002774#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002775 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002776#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002777 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002778#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002779 if (retval == OK)
2780 // Apply SourcePost autocommands.
2781 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
2782 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002783 goto theend;
2784 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002785
2786 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002787 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002788
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002789#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2791#else
2792 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2793#endif
2794 if (cookie.fp == NULL && check_other)
2795 {
2796 /*
2797 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2798 * and ".exrc" by "_exrc" or vice versa.
2799 */
2800 p = gettail(fname_exp);
2801 if ((*p == '.' || *p == '_')
2802 && (STRICMP(p + 1, "vimrc") == 0
2803 || STRICMP(p + 1, "gvimrc") == 0
2804 || STRICMP(p + 1, "exrc") == 0))
2805 {
2806 if (*p == '_')
2807 *p = '.';
2808 else
2809 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002810#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2812#else
2813 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2814#endif
2815 }
2816 }
2817
2818 if (cookie.fp == NULL)
2819 {
2820 if (p_verbose > 0)
2821 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002822 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002823 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002824 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002826 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002827 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002828 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829 }
2830 goto theend;
2831 }
2832
2833 /*
2834 * The file exists.
2835 * - In verbose mode, give a message.
2836 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2837 */
2838 if (p_verbose > 1)
2839 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002840 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002842 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002844 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002845 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002846 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002848 if (is_vimrc == DOSO_VIMRC)
2849 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2850 else if (is_vimrc == DOSO_GVIMRC)
2851 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852
2853#ifdef USE_CRNL
2854 /* If no automatic file format: Set default to CR-NL. */
2855 if (*p_ffs == NUL)
2856 cookie.fileformat = EOL_DOS;
2857 else
2858 cookie.fileformat = EOL_UNKNOWN;
2859 cookie.error = FALSE;
2860#endif
2861
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862 cookie.nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002863 cookie.sourcing_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864 cookie.finished = FALSE;
2865
2866#ifdef FEAT_EVAL
2867 /*
2868 * Check if this script has a breakpoint.
2869 */
2870 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2871 cookie.fname = fname_exp;
2872 cookie.dbg_tick = debug_tick;
2873
2874 cookie.level = ex_nesting_level;
2875#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876
2877 /*
2878 * Keep the sourcing name/lnum, for recursive calls.
2879 */
2880 save_sourcing_name = sourcing_name;
2881 sourcing_name = fname_exp;
2882 save_sourcing_lnum = sourcing_lnum;
2883 sourcing_lnum = 0;
2884
2885#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01002886 if (time_fd != NULL)
2887 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888#endif
2889
2890#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00002891# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002892 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002893 prof_child_enter(&wait_start); /* entering a child now */
2894# endif
2895
2896 /* Don't use local function variables, if called from a function.
2897 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002898 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002899
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002900 save_current_sctx = current_sctx;
2901 current_sctx.sc_lnum = 0;
2902 current_sctx.sc_version = 1;
2903
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002904 // Check if this script was sourced before to finds its SID.
2905 // If it's new, generate a new SID.
2906 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002907 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908# ifdef UNIX
2909 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2910# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002911 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
2912 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002913 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002914 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002915 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916 && (
2917# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00002918 /* Compare dev/ino when possible, it catches symbolic
2919 * links. Also compare file names, the inode may change
2920 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002921 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002922 && (si->sn_dev == st.st_dev
2923 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002925 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002927 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002928 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002929 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002930 current_sctx.sc_sid = ++last_current_SID;
2931 if (ga_grow(&script_items,
2932 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002933 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002934 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002936 ++script_items.ga_len;
2937 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
2938# ifdef FEAT_PROFILE
2939 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002942 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002943 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01002944 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00002945# ifdef UNIX
2946 if (stat_ok)
2947 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002948 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002949 si->sn_dev = st.st_dev;
2950 si->sn_ino = st.st_ino;
2951 }
2952 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002953 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002954# endif
2955
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002957 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 }
2959
Bram Moolenaar05159a02005-02-26 23:04:13 +00002960# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002961 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002962 {
2963 int forceit;
2964
2965 /* Check if we do profiling for this script. */
2966 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
2967 {
2968 script_do_profile(si);
2969 si->sn_pr_force = forceit;
2970 }
2971 if (si->sn_prof_on)
2972 {
2973 ++si->sn_pr_count;
2974 profile_start(&si->sn_pr_start);
2975 profile_zero(&si->sn_pr_children);
2976 }
2977 }
2978# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979#endif
2980
Bram Moolenaar67435d92017-10-19 21:04:37 +02002981 cookie.conv.vc_type = CONV_NONE; /* no conversion */
2982
2983 /* Read the first line so we can check for a UTF-8 BOM. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02002984 firstline = getsourceline(0, (void *)&cookie, 0, TRUE);
Bram Moolenaar67435d92017-10-19 21:04:37 +02002985 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
2986 && firstline[1] == 0xbb && firstline[2] == 0xbf)
2987 {
2988 /* Found BOM; setup conversion, skip over BOM and recode the line. */
2989 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
2990 p = string_convert(&cookie.conv, firstline + 3, NULL);
2991 if (p == NULL)
2992 p = vim_strsave(firstline + 3);
2993 if (p != NULL)
2994 {
2995 vim_free(firstline);
2996 firstline = p;
2997 }
2998 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02002999
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 /*
3001 * Call do_cmdline, which will call getsourceline() to get the lines.
3002 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003003 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003006
3007#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003008 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003009 {
3010 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003011 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003012 if (si->sn_prof_on)
3013 {
3014 profile_end(&si->sn_pr_start);
3015 profile_sub_wait(&wait_start, &si->sn_pr_start);
3016 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003017 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3018 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003019 }
3020 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021#endif
3022
3023 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003024 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 sourcing_name = save_sourcing_name;
3026 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003027 if (p_verbose > 1)
3028 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003029 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003030 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003032 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003033 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 }
3035#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003036 if (time_fd != NULL)
3037 {
3038 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3039 time_msg((char *)IObuff, &tv_start);
3040 time_pop(&tv_rel);
3041 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042#endif
3043
Bram Moolenaar2b618522019-01-12 13:26:03 +01003044 if (!got_int)
3045 trigger_source_post = TRUE;
3046
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047#ifdef FEAT_EVAL
3048 /*
3049 * After a "finish" in debug mode, need to break at first command of next
3050 * sourced file.
3051 */
3052 if (save_debug_break_level > ex_nesting_level
3053 && debug_break_level == ex_nesting_level)
3054 ++debug_break_level;
3055#endif
3056
Bram Moolenaar05159a02005-02-26 23:04:13 +00003057#ifdef FEAT_EVAL
3058almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003059 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003060 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003061# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003062 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003063 prof_child_exit(&wait_start); /* leaving a child now */
3064# endif
3065#endif
3066 fclose(cookie.fp);
3067 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003068 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003069 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003070
Bram Moolenaar2b618522019-01-12 13:26:03 +01003071 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003072 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003073
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074theend:
3075 vim_free(fname_exp);
3076 return retval;
3077}
3078
3079#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003080
Bram Moolenaar071d4272004-06-13 20:20:40 +00003081/*
3082 * ":scriptnames"
3083 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003085ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086{
3087 int i;
3088
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003089 if (eap->addr_count > 0)
3090 {
3091 // :script {scriptId}: edit the script
3092 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003093 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003094 else
3095 {
3096 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3097 do_exedit(eap, NULL);
3098 }
3099 return;
3100 }
3101
Bram Moolenaar05159a02005-02-26 23:04:13 +00003102 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3103 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003104 {
3105 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3106 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003107 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003108 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109}
3110
3111# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3112/*
3113 * Fix slashes in the list of script names for 'shellslash'.
3114 */
3115 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003116scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003117{
3118 int i;
3119
Bram Moolenaar05159a02005-02-26 23:04:13 +00003120 for (i = 1; i <= script_items.ga_len; ++i)
3121 if (SCRIPT_ITEM(i).sn_name != NULL)
3122 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003123}
3124# endif
3125
3126/*
3127 * Get a pointer to a script name. Used for ":verbose set".
3128 */
3129 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003130get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131{
3132 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003133 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003135 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003137 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003139 return (char_u *)_("environment variable");
3140 if (id == SID_ERROR)
3141 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003142 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003144
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003145# if defined(EXITFREE) || defined(PROTO)
3146 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003147free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003148{
3149 int i;
3150
3151 for (i = script_items.ga_len; i > 0; --i)
3152 vim_free(SCRIPT_ITEM(i).sn_name);
3153 ga_clear(&script_items);
3154}
3155# endif
3156
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157#endif
3158
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003159 linenr_T
3160get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), void *cookie)
3161{
3162 return fgetline == getsourceline
3163 ? ((struct source_cookie *)cookie)->sourcing_lnum
3164 : sourcing_lnum;
3165}
3166
Bram Moolenaar071d4272004-06-13 20:20:40 +00003167/*
3168 * Get one full line from a sourced file.
3169 * Called by do_cmdline() when it's called from do_source().
3170 *
3171 * Return a pointer to the line in allocated memory.
3172 * Return NULL for end-of-file or some error.
3173 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 char_u *
Bram Moolenaare96a2492019-06-25 04:12:16 +02003175getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176{
3177 struct source_cookie *sp = (struct source_cookie *)cookie;
3178 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003179 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180
3181#ifdef FEAT_EVAL
3182 /* If breakpoints have been added/deleted need to check for it. */
3183 if (sp->dbg_tick < debug_tick)
3184 {
3185 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3186 sp->dbg_tick = debug_tick;
3187 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003188# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003189 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003190 script_line_end();
3191# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003193
3194 // Set the current sourcing line number.
3195 sourcing_lnum = sp->sourcing_lnum + 1;
3196
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197 /*
3198 * Get current line. If there is a read-ahead line, use it, otherwise get
3199 * one now.
3200 */
3201 if (sp->finished)
3202 line = NULL;
3203 else if (sp->nextline == NULL)
3204 line = get_one_sourceline(sp);
3205 else
3206 {
3207 line = sp->nextline;
3208 sp->nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003209 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003211#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003212 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003213 script_line_start();
3214#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215
3216 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3217 * contain the 'C' flag. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02003218 if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219 {
3220 /* compensate for the one line read-ahead */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003221 --sp->sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003222
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003223 // Get the next line and concatenate it when it starts with a
3224 // backslash. We always need to read the next line, keep it in
3225 // sp->nextline.
3226 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003227 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003228 if (sp->nextline != NULL
3229 && (*(p = skipwhite(sp->nextline)) == '\\'
3230 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003232 garray_T ga;
3233
Bram Moolenaarb549a732012-02-22 18:29:33 +01003234 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003235 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003236 if (*p == '\\')
3237 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003238 for (;;)
3239 {
3240 vim_free(sp->nextline);
3241 sp->nextline = get_one_sourceline(sp);
3242 if (sp->nextline == NULL)
3243 break;
3244 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003245 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003246 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003247 // Adjust the growsize to the current length to speed up
3248 // concatenating many lines.
3249 if (ga.ga_len > 400)
3250 {
3251 if (ga.ga_len > 8000)
3252 ga.ga_growsize = 8000;
3253 else
3254 ga.ga_growsize = ga.ga_len;
3255 }
3256 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003257 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003258 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3259 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003260 }
3261 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003263 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264 }
3265 }
3266
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3268 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003269 char_u *s;
3270
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271 /* Convert the encoding of the script line. */
3272 s = string_convert(&sp->conv, line, NULL);
3273 if (s != NULL)
3274 {
3275 vim_free(line);
3276 line = s;
3277 }
3278 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279
3280#ifdef FEAT_EVAL
3281 /* Did we encounter a breakpoint? */
3282 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3283 {
3284 dbg_breakpoint(sp->fname, sourcing_lnum);
3285 /* Find next breakpoint. */
3286 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3287 sp->dbg_tick = debug_tick;
3288 }
3289#endif
3290
3291 return line;
3292}
3293
3294 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003295get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296{
3297 garray_T ga;
3298 int len;
3299 int c;
3300 char_u *buf;
3301#ifdef USE_CRNL
3302 int has_cr; /* CR-LF found */
3303#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304 int have_read = FALSE;
3305
3306 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003307 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003308
3309 /*
3310 * Loop until there is a finished line (or end-of-file).
3311 */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003312 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313 for (;;)
3314 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003315 /* make room to read at least 120 (more) characters */
3316 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 break;
3318 buf = (char_u *)ga.ga_data;
3319
Bram Moolenaar00590742019-02-15 21:06:09 +01003320 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003321 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003322 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003323 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324#ifdef USE_CRNL
3325 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3326 * CTRL-Z by its own, or after a NL. */
3327 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3328 && sp->fileformat == EOL_DOS
3329 && buf[len - 1] == Ctrl_Z)
3330 {
3331 buf[len - 1] = NUL;
3332 break;
3333 }
3334#endif
3335
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 ga.ga_len = len;
3338
3339 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003340 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 continue;
3342
3343 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3344 {
3345#ifdef USE_CRNL
3346 has_cr = (len >= 2 && buf[len - 2] == '\r');
3347 if (sp->fileformat == EOL_UNKNOWN)
3348 {
3349 if (has_cr)
3350 sp->fileformat = EOL_DOS;
3351 else
3352 sp->fileformat = EOL_UNIX;
3353 }
3354
3355 if (sp->fileformat == EOL_DOS)
3356 {
3357 if (has_cr) /* replace trailing CR */
3358 {
3359 buf[len - 2] = '\n';
3360 --len;
3361 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362 }
3363 else /* lines like ":map xx yy^M" will have failed */
3364 {
3365 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003366 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003367 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003368 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003369 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 sp->error = TRUE;
3371 sp->fileformat = EOL_UNIX;
3372 }
3373 }
3374#endif
3375 /* The '\n' is escaped if there is an odd number of ^V's just
3376 * before it, first set "c" just before the 'V's and then check
3377 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3378 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3379 ;
3380 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3381 {
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003382 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383 continue;
3384 }
3385
3386 buf[len - 1] = NUL; /* remove the NL */
3387 }
3388
3389 /*
3390 * Check for ^C here now and then, so recursive :so can be broken.
3391 */
3392 line_breakcheck();
3393 break;
3394 }
3395
3396 if (have_read)
3397 return (char_u *)ga.ga_data;
3398
3399 vim_free(ga.ga_data);
3400 return NULL;
3401}
3402
3403/*
3404 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003407ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003408{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409 struct source_cookie *sp;
3410 char_u *name;
3411
3412 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3413 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003414 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003415 return;
3416 }
3417
3418 if (*eap->arg != NUL)
3419 {
3420 name = enc_canonize(eap->arg);
3421 if (name == NULL) /* out of memory */
3422 return;
3423 }
3424 else
3425 name = eap->arg;
3426
3427 /* Setup for conversion from the specified encoding to 'encoding'. */
3428 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3429 convert_setup(&sp->conv, name, p_enc);
3430
3431 if (name != eap->arg)
3432 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433}
3434
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003435/*
3436 * ":scriptversion": Set Vim script version for a sourced script.
3437 */
3438 void
3439ex_scriptversion(exarg_T *eap UNUSED)
3440{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02003441#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003442 int nr;
3443
3444 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3445 {
3446 emsg(_("E984: :scriptversion used outside of a sourced file"));
3447 return;
3448 }
3449
3450 nr = getdigits(&eap->arg);
3451 if (nr == 0 || *eap->arg != NUL)
3452 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02003453 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003454 semsg(_("E999: scriptversion not supported: %d"), nr);
3455 else
3456 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02003457#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003458}
3459
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460#if defined(FEAT_EVAL) || defined(PROTO)
3461/*
3462 * ":finish": Mark a sourced file as finished.
3463 */
3464 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003465ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466{
3467 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3468 do_finish(eap, FALSE);
3469 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003470 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471}
3472
3473/*
3474 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3475 * Also called for a pending finish at the ":endtry" or after returning from
3476 * an extra do_cmdline(). "reanimate" is used in the latter case.
3477 */
3478 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003479do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480{
3481 int idx;
3482
3483 if (reanimate)
3484 ((struct source_cookie *)getline_cookie(eap->getline,
3485 eap->cookie))->finished = FALSE;
3486
3487 /*
3488 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3489 * not in its finally clause (which then is to be executed next) is found.
3490 * In this case, make the ":finish" pending for execution at the ":endtry".
3491 * Otherwise, finish normally.
3492 */
3493 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3494 if (idx >= 0)
3495 {
3496 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3497 report_make_pending(CSTP_FINISH, NULL);
3498 }
3499 else
3500 ((struct source_cookie *)getline_cookie(eap->getline,
3501 eap->cookie))->finished = TRUE;
3502}
3503
3504
3505/*
3506 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3507 * message for missing ":endif".
3508 * Return FALSE when not sourcing a file.
3509 */
3510 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003511source_finished(
Bram Moolenaare96a2492019-06-25 04:12:16 +02003512 char_u *(*fgetline)(int, void *, int, int),
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003513 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003515 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003517 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518}
3519#endif
3520
Bram Moolenaar071d4272004-06-13 20:20:40 +00003521/*
3522 * ":checktime [buffer]"
3523 */
3524 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003525ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526{
3527 buf_T *buf;
3528 int save_no_check_timestamps = no_check_timestamps;
3529
3530 no_check_timestamps = 0;
3531 if (eap->addr_count == 0) /* default is all buffers */
3532 check_timestamps(FALSE);
3533 else
3534 {
3535 buf = buflist_findnr((int)eap->line2);
3536 if (buf != NULL) /* cannot happen? */
3537 (void)buf_check_timestamp(buf, FALSE);
3538 }
3539 no_check_timestamps = save_no_check_timestamps;
3540}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3543 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003544# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003545 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003546get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003547{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003548 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003549
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003550 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003551 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552
Bram Moolenaar4f974752019-02-17 17:44:42 +01003553# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 if (loc != NULL)
3555 {
3556 char_u *p;
3557
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003558 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3559 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 p = vim_strchr(loc, '=');
3561 if (p != NULL)
3562 {
3563 loc = ++p;
3564 while (*p != NUL) /* remove trailing newline */
3565 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003566 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567 {
3568 *p = NUL;
3569 break;
3570 }
3571 ++p;
3572 }
3573 }
3574 }
3575# endif
3576
3577 return loc;
3578}
3579#endif
3580
3581
Bram Moolenaar4f974752019-02-17 17:44:42 +01003582#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583/*
3584 * On MS-Windows locale names are strings like "German_Germany.1252", but
3585 * gettext expects "de". Try to translate one into another here for a few
3586 * supported languages.
3587 */
3588 static char_u *
3589gettext_lang(char_u *name)
3590{
3591 int i;
3592 static char *(mtable[]) = {
3593 "afrikaans", "af",
3594 "czech", "cs",
3595 "dutch", "nl",
3596 "german", "de",
3597 "english_united kingdom", "en_GB",
3598 "spanish", "es",
3599 "french", "fr",
3600 "italian", "it",
3601 "japanese", "ja",
3602 "korean", "ko",
3603 "norwegian", "no",
3604 "polish", "pl",
3605 "russian", "ru",
3606 "slovak", "sk",
3607 "swedish", "sv",
3608 "ukrainian", "uk",
3609 "chinese_china", "zh_CN",
3610 "chinese_taiwan", "zh_TW",
3611 NULL};
3612
3613 for (i = 0; mtable[i] != NULL; i += 2)
3614 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003615 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616 return name;
3617}
3618#endif
3619
3620#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3621/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01003622 * Return TRUE when "lang" starts with a valid language name.
3623 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
3624 */
3625 static int
3626is_valid_mess_lang(char_u *lang)
3627{
3628 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
3629}
3630
3631/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003632 * Obtain the current messages language. Used to set the default for
3633 * 'helplang'. May return NULL or an empty string.
3634 */
3635 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003636get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637{
3638 char_u *p;
3639
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003640# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003641# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003642 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643# else
3644 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003645 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3646 * and LC_MONETARY may be set differently for a Japanese working in the
3647 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003648 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649# endif
3650# else
3651 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003652 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653 {
3654 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003655 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656 p = mch_getenv((char_u *)"LANG");
3657 }
3658# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003659# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660 p = gettext_lang(p);
3661# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01003662 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663}
3664#endif
3665
Bram Moolenaardef9e822004-12-31 20:58:58 +00003666/* Complicated #if; matches with where get_mess_env() is used below. */
3667#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3668 && defined(LC_MESSAGES))) \
3669 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00003670 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671/*
3672 * Get the language used for messages from the environment.
3673 */
3674 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003675get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676{
3677 char_u *p;
3678
3679 p = mch_getenv((char_u *)"LC_ALL");
3680 if (p == NULL || *p == NUL)
3681 {
3682 p = mch_getenv((char_u *)"LC_MESSAGES");
3683 if (p == NULL || *p == NUL)
3684 {
3685 p = mch_getenv((char_u *)"LANG");
3686 if (p != NULL && VIM_ISDIGIT(*p))
3687 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003688# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003690 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691# endif
3692 }
3693 }
3694 return p;
3695}
3696#endif
3697
3698#if defined(FEAT_EVAL) || defined(PROTO)
3699
3700/*
3701 * Set the "v:lang" variable according to the current locale setting.
3702 * Also do "v:lc_time"and "v:ctype".
3703 */
3704 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003705set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706{
3707 char_u *loc;
3708
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003709# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003710 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711# else
3712 /* setlocale() not supported: use the default value */
3713 loc = (char_u *)"C";
3714# endif
3715 set_vim_var_string(VV_CTYPE, loc, -1);
3716
3717 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3718 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003719# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003720 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721# else
3722 loc = get_mess_env();
3723# endif
3724 set_vim_var_string(VV_LANG, loc, -1);
3725
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003726# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003727 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728# endif
3729 set_vim_var_string(VV_LC_TIME, loc, -1);
3730}
3731#endif
3732
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01003733#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734/*
3735 * ":language": Set the language (locale).
3736 */
3737 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003738ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739{
3740 char *loc;
3741 char_u *p;
3742 char_u *name;
3743 int what = LC_ALL;
3744 char *whatstr = "";
3745#ifdef LC_MESSAGES
3746# define VIM_LC_MESSAGES LC_MESSAGES
3747#else
3748# define VIM_LC_MESSAGES 6789
3749#endif
3750
3751 name = eap->arg;
3752
3753 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3754 * Allow abbreviation, but require at least 3 characters to avoid
3755 * confusion with a two letter language name "me" or "ct". */
3756 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003757 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758 {
3759 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3760 {
3761 what = VIM_LC_MESSAGES;
3762 name = skipwhite(p);
3763 whatstr = "messages ";
3764 }
3765 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3766 {
3767 what = LC_CTYPE;
3768 name = skipwhite(p);
3769 whatstr = "ctype ";
3770 }
3771 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3772 {
3773 what = LC_TIME;
3774 name = skipwhite(p);
3775 whatstr = "time ";
3776 }
3777 }
3778
3779 if (*name == NUL)
3780 {
3781#ifndef LC_MESSAGES
3782 if (what == VIM_LC_MESSAGES)
3783 p = get_mess_env();
3784 else
3785#endif
3786 p = (char_u *)setlocale(what, NULL);
3787 if (p == NULL || *p == NUL)
3788 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003789 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790 }
3791 else
3792 {
3793#ifndef LC_MESSAGES
3794 if (what == VIM_LC_MESSAGES)
3795 loc = "";
3796 else
3797#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003798 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003800#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
3801 /* Make sure strtod() uses a decimal point, not a comma. */
3802 setlocale(LC_NUMERIC, "C");
3803#endif
3804 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003806 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003807 else
3808 {
3809#ifdef HAVE_NL_MSG_CAT_CNTR
3810 /* Need to do this for GNU gettext, otherwise cached translations
3811 * will be used again. */
3812 extern int _nl_msg_cat_cntr;
3813
3814 ++_nl_msg_cat_cntr;
3815#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00003816 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
3818
3819 if (what != LC_TIME)
3820 {
3821 /* Tell gettext() what to translate to. It apparently doesn't
3822 * use the currently effective locale. Also do this when
3823 * FEAT_GETTEXT isn't defined, so that shell commands use this
3824 * value. */
3825 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003826 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02003828
3829 /* Clear $LANGUAGE because GNU gettext uses it. */
3830 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01003831# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003832 /* Apparently MS-Windows printf() may cause a crash when
3833 * we give it 8-bit text while it's expecting text in the
3834 * current locale. This call avoids that. */
3835 setlocale(LC_CTYPE, "C");
3836# endif
3837 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003838 if (what != LC_CTYPE)
3839 {
3840 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003841#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003842 mname = gettext_lang(name);
3843#else
3844 mname = name;
3845#endif
3846 vim_setenv((char_u *)"LC_MESSAGES", mname);
3847#ifdef FEAT_MULTI_LANG
3848 set_helplang_default(mname);
3849#endif
3850 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003851 }
3852
3853# ifdef FEAT_EVAL
3854 /* Set v:lang, v:lc_time and v:ctype to the final result. */
3855 set_lang_var();
3856# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02003857# ifdef FEAT_TITLE
3858 maketitle();
3859# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003860 }
3861 }
3862}
3863
3864# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003865
3866static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003867
Bram Moolenaar4f974752019-02-17 17:44:42 +01003868# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003869static int did_init_locales = FALSE;
3870
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003871/* Return an array of strings for all available locales + NULL for the
3872 * last element. Return NULL in case of error. */
3873 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003874find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003875{
3876 garray_T locales_ga;
3877 char_u *loc;
3878
3879 /* Find all available locales by running command "locale -a". If this
3880 * doesn't work we won't have completion. */
3881 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02003882 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003883 if (locale_a == NULL)
3884 return NULL;
3885 ga_init2(&locales_ga, sizeof(char_u *), 20);
3886
3887 /* Transform locale_a string where each locale is separated by "\n"
3888 * into an array of locale strings. */
3889 loc = (char_u *)strtok((char *)locale_a, "\n");
3890
3891 while (loc != NULL)
3892 {
3893 if (ga_grow(&locales_ga, 1) == FAIL)
3894 break;
3895 loc = vim_strsave(loc);
3896 if (loc == NULL)
3897 break;
3898
3899 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
3900 loc = (char_u *)strtok(NULL, "\n");
3901 }
3902 vim_free(locale_a);
3903 if (ga_grow(&locales_ga, 1) == FAIL)
3904 {
3905 ga_clear(&locales_ga);
3906 return NULL;
3907 }
3908 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
3909 return (char_u **)locales_ga.ga_data;
3910}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003911# endif
3912
3913/*
3914 * Lazy initialization of all available locales.
3915 */
3916 static void
3917init_locales(void)
3918{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003919# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003920 if (!did_init_locales)
3921 {
3922 did_init_locales = TRUE;
3923 locales = find_locales();
3924 }
3925# endif
3926}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003927
3928# if defined(EXITFREE) || defined(PROTO)
3929 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003930free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003931{
3932 int i;
3933 if (locales != NULL)
3934 {
3935 for (i = 0; locales[i] != NULL; i++)
3936 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01003937 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003938 }
3939}
3940# endif
3941
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942/*
3943 * Function given to ExpandGeneric() to obtain the possible arguments of the
3944 * ":language" command.
3945 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003947get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948{
3949 if (idx == 0)
3950 return (char_u *)"messages";
3951 if (idx == 1)
3952 return (char_u *)"ctype";
3953 if (idx == 2)
3954 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003955
3956 init_locales();
3957 if (locales == NULL)
3958 return NULL;
3959 return locales[idx - 3];
3960}
3961
3962/*
3963 * Function given to ExpandGeneric() to obtain the available locales.
3964 */
3965 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003966get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003967{
3968 init_locales();
3969 if (locales == NULL)
3970 return NULL;
3971 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972}
3973# endif
3974
3975#endif