blob: c44ac8da171af8a246325fd9216f859cee448a9c [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;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100113 typval_T argv[2];
114
115 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200116 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100117 argv[1].v_type = VAR_UNKNOWN;
118
Bram Moolenaarc6538bc2019-08-03 18:17:11 +0200119 call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100120 clear_tv(&rettv);
121}
122
123/*
124 * Call timers that are due.
125 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200126 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100127 */
128 long
Bram Moolenaarcf089462016-06-12 21:18:43 +0200129check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100130{
131 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200132 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100133 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +0100134 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100135 proftime_T now;
136 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200137 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200138 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100139
Bram Moolenaarc577d812017-07-08 22:37:34 +0200140 /* Don't run any timers while exiting or dealing with an error. */
141 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200142 return next_due;
143
Bram Moolenaar75537a92016-09-05 22:45:28 +0200144 profile_start(&now);
145 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100146 {
Bram Moolenaar75537a92016-09-05 22:45:28 +0200147 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200148
Bram Moolenaar75537a92016-09-05 22:45:28 +0200149 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
150 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100151 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200152 if (this_due <= 1)
153 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200154 /* Save and restore a lot of flags, because the timer fires while
155 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200156 int save_timer_busy = timer_busy;
157 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200158 int save_did_emsg = did_emsg;
159 int save_called_emsg = called_emsg;
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200160 int save_must_redraw = must_redraw;
161 int save_trylevel = trylevel;
Bram Moolenaare723c422017-09-06 23:40:10 +0200162 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200163 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare96a2492019-06-25 04:12:16 +0200164 int save_may_garbage_collect = may_garbage_collect;
Bram Moolenaare723c422017-09-06 23:40:10 +0200165 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200166 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200167
Bram Moolenaare723c422017-09-06 23:40:10 +0200168 /* Create a scope for running the timer callback, ignoring most of
169 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200170 timer_busy = timer_busy > 0 || vgetc_busy > 0;
171 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +0200172 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200173 did_emsg = FALSE;
174 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200175 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +0200176 trylevel = 0;
177 did_throw = FALSE;
178 current_exception = NULL;
Bram Moolenaare96a2492019-06-25 04:12:16 +0200179 may_garbage_collect = FALSE;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200180 save_vimvars(&vvsave);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200181
Bram Moolenaar75537a92016-09-05 22:45:28 +0200182 timer->tr_firing = TRUE;
183 timer_callback(timer);
184 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200185
Bram Moolenaar75537a92016-09-05 22:45:28 +0200186 timer_next = timer->tr_next;
187 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200188 timer_busy = save_timer_busy;
189 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200190 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200191 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200192 did_emsg = save_did_emsg;
193 called_emsg = save_called_emsg;
194 trylevel = save_trylevel;
195 did_throw = save_did_throw;
196 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200197 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200198 if (must_redraw != 0)
199 need_update_screen = TRUE;
200 must_redraw = must_redraw > save_must_redraw
201 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200202 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200203 may_garbage_collect = save_may_garbage_collect;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200204
205 /* Only fire the timer again if it repeats and stop_timer() wasn't
206 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200207 if (timer->tr_repeat != 0 && timer->tr_id != -1
208 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200209 {
210 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100211 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200212 if (this_due < 1)
213 this_due = 1;
214 if (timer->tr_repeat > 0)
215 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100216 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200217 else
218 {
219 this_due = -1;
220 remove_timer(timer);
221 free_timer(timer);
222 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100223 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200224 if (this_due > 0 && (next_due == -1 || next_due > this_due))
225 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100226 }
227
228 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200229 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100230
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100231#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100232 if (bevalexpr_due_set)
233 {
234 this_due = proftime_time_left(&bevalexpr_due, &now);
235 if (this_due <= 1)
236 {
237 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100238 if (balloonEval == NULL)
239 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200240 balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100241 balloonEvalForTerm = TRUE;
242 }
243 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200244 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100245 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200246 setcursor();
247 out_flush();
248 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100249 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200250 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100251 next_due = this_due;
252 }
253#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200254#ifdef FEAT_TERMINAL
255 /* Some terminal windows may need their buffer updated. */
256 next_due = term_check_timers(next_due, &now);
257#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100258
Bram Moolenaar75537a92016-09-05 22:45:28 +0200259 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100260}
261
262/*
263 * Find a timer by ID. Returns NULL if not found;
264 */
265 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200266find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100267{
268 timer_T *timer;
269
Bram Moolenaar75537a92016-09-05 22:45:28 +0200270 if (id >= 0)
271 {
272 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
273 if (timer->tr_id == id)
274 return timer;
275 }
276 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100277}
278
279
280/*
281 * Stop a timer and delete it.
282 */
283 void
284stop_timer(timer_T *timer)
285{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200286 if (timer->tr_firing)
287 /* Free the timer after the callback returns. */
288 timer->tr_id = -1;
289 else
290 {
291 remove_timer(timer);
292 free_timer(timer);
293 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100294}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200295
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200296 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200297stop_all_timers(void)
298{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200299 timer_T *timer;
300 timer_T *timer_next;
301
302 for (timer = first_timer; timer != NULL; timer = timer_next)
303 {
304 timer_next = timer->tr_next;
305 stop_timer(timer);
306 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200307}
308
309 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200310add_timer_info(typval_T *rettv, timer_T *timer)
311{
312 list_T *list = rettv->vval.v_list;
313 dict_T *dict = dict_alloc();
314 dictitem_T *di;
315 long remaining;
316 proftime_T now;
317
318 if (dict == NULL)
319 return;
320 list_append_dict(list, dict);
321
Bram Moolenaare0be1672018-07-08 16:50:37 +0200322 dict_add_number(dict, "id", timer->tr_id);
323 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200324
325 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100326 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200327 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200328
Bram Moolenaare0be1672018-07-08 16:50:37 +0200329 dict_add_number(dict, "repeat",
330 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
331 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200332
333 di = dictitem_alloc((char_u *)"callback");
334 if (di != NULL)
335 {
336 if (dict_add(dict, di) == FAIL)
337 vim_free(di);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200338 else
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200339 put_callback(&timer->tr_callback, &di->di_tv);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200340 }
341}
342
343 void
344add_timer_info_all(typval_T *rettv)
345{
346 timer_T *timer;
347
348 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200349 if (timer->tr_id != -1)
350 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200351}
352
Bram Moolenaare3188e22016-05-31 21:13:04 +0200353/*
354 * Mark references in partials of timers.
355 */
356 int
357set_ref_in_timer(int copyID)
358{
359 int abort = FALSE;
360 timer_T *timer;
361 typval_T tv;
362
Bram Moolenaar75a1a942019-06-20 03:45:36 +0200363 for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
Bram Moolenaare3188e22016-05-31 21:13:04 +0200364 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200365 if (timer->tr_callback.cb_partial != NULL)
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200366 {
367 tv.v_type = VAR_PARTIAL;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200368 tv.vval.v_partial = timer->tr_callback.cb_partial;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200369 }
370 else
371 {
372 tv.v_type = VAR_FUNC;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200373 tv.vval.v_string = timer->tr_callback.cb_name;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200374 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200375 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
376 }
377 return abort;
378}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200379
380# if defined(EXITFREE) || defined(PROTO)
381 void
382timer_free_all()
383{
384 timer_T *timer;
385
386 while (first_timer != NULL)
387 {
388 timer = first_timer;
389 remove_timer(timer);
390 free_timer(timer);
391 }
392}
393# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100394# endif
395
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396#endif
397
398/*
399 * If 'autowrite' option set, try to write the file.
400 * Careful: autocommands may make "buf" invalid!
401 *
402 * return FAIL for failure, OK otherwise
403 */
404 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100405autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406{
Bram Moolenaar373154b2007-02-13 05:19:30 +0000407 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200408 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +0000409
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410 if (!(p_aw || p_awa) || !p_write
411#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +0000412 /* never autowrite a "nofile" or "nowrite" buffer */
413 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000414#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +0000415 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200417 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +0000418 r = buf_write_all(buf, forceit);
419
420 /* Writing may succeed but the buffer still changed, e.g., when there is a
421 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200422 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +0000423 r = FAIL;
424 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425}
426
427/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200428 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429 */
430 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100431autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432{
433 buf_T *buf;
434
435 if (!(p_aw || p_awa) || !p_write)
436 return;
Bram Moolenaar29323592016-07-24 22:04:11 +0200437 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200438 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200440 bufref_T bufref;
441
442 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100443
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100445
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200447 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449 }
450}
451
452/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100453 * Return TRUE if buffer was changed and cannot be abandoned.
454 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100457check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200459 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200460 bufref_T bufref;
461
462 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100463
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464 if ( !forceit
465 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100466 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
467 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468 {
469#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
470 if ((p_confirm || cmdmod.confirm) && p_write)
471 {
472 buf_T *buf2;
473 int count = 0;
474
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100475 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +0200476 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 if (bufIsChanged(buf2)
478 && (buf2->b_ffname != NULL
479# ifdef FEAT_BROWSE
480 || cmdmod.browse
481# endif
482 ))
483 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200484 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485 /* Autocommand deleted buffer, oops! It's not changed now. */
486 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100487
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100489
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200490 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 /* Autocommand deleted buffer, oops! It's not changed now. */
492 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000493 return bufIsChanged(buf);
494 }
495#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100496 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +0200497 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100498 else
Bram Moolenaar7a760922018-02-19 23:10:02 +0100499 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 return TRUE;
501 }
502 return FALSE;
503}
504
505#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
506
507#if defined(FEAT_BROWSE) || defined(PROTO)
508/*
509 * When wanting to write a file without a file name, ask the user for a name.
510 */
511 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100512browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513{
514 if (buf->b_fname == NULL)
515 {
516 char_u *fname;
517
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000518 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
519 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520 if (fname != NULL)
521 {
522 if (setfname(buf, fname, NULL, TRUE) == OK)
523 buf->b_flags |= BF_NOTEDITED;
524 vim_free(fname);
525 }
526 }
527}
528#endif
529
530/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +0200531 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 * Must check 'write' option first!
533 */
534 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100535dialog_changed(
536 buf_T *buf,
537 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000538{
Bram Moolenaard9462e32011-04-11 21:35:11 +0200539 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 int ret;
541 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +0200542 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +0200544 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 if (checkall)
546 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
547 else
548 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
549
Bram Moolenaar4ca41532019-05-09 21:48:37 +0200550 // Init ea pseudo-structure, this is needed for the check_overwrite()
551 // function.
552 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +0200553
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 if (ret == VIM_YES)
555 {
556#ifdef FEAT_BROWSE
557 /* May get file name, when there is none */
558 browse_save_fname(buf);
559#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200560 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
561 buf->b_fname, buf->b_ffname, FALSE) == OK)
562 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 (void)buf_write_all(buf, FALSE);
564 }
565 else if (ret == VIM_NO)
566 {
Bram Moolenaarc024b462019-06-08 18:07:21 +0200567 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 }
569 else if (ret == VIM_ALL)
570 {
571 /*
572 * Write all modified files that can be written.
573 * Skip readonly buffers, these need to be confirmed
574 * individually.
575 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200576 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577 {
578 if (bufIsChanged(buf2)
579 && (buf2->b_ffname != NULL
580#ifdef FEAT_BROWSE
581 || cmdmod.browse
582#endif
583 )
584 && !buf2->b_p_ro)
585 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200586 bufref_T bufref;
587
588 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589#ifdef FEAT_BROWSE
590 /* May get file name, when there is none */
591 browse_save_fname(buf2);
592#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200593 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
594 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
595 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100597
Bram Moolenaar071d4272004-06-13 20:20:40 +0000598 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200599 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601 }
602 }
603 }
604 else if (ret == VIM_DISCARDALL)
605 {
606 /*
607 * mark all buffers as unchanged
608 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200609 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +0200610 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 }
612}
613#endif
614
615/*
616 * Return TRUE if the buffer "buf" can be abandoned, either by making it
617 * hidden, autowriting it or unloading it.
618 */
619 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100620can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621{
Bram Moolenaareb44a682017-08-03 22:44:55 +0200622 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623 || !bufIsChanged(buf)
624 || buf->b_nwindows > 1
625 || autowrite(buf, forceit) == OK
626 || forceit);
627}
628
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100629/*
630 * Add a buffer number to "bufnrs", unless it's already there.
631 */
632 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100633add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100634{
635 int i;
636
637 for (i = 0; i < *bufnump; ++i)
638 if (bufnrs[i] == nr)
639 return;
640 bufnrs[*bufnump] = nr;
641 *bufnump = *bufnump + 1;
642}
643
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644/*
645 * Return TRUE if any buffer was changed and cannot be abandoned.
646 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100647 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +0100648 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 */
650 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100651check_changed_any(
652 int hidden, /* Only check hidden buffers */
653 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654{
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100655 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656 buf_T *buf;
657 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100658 int i;
659 int bufnum = 0;
660 int bufcount = 0;
661 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100662 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100665 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +0200666 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100667 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100669 if (bufcount == 0)
670 return FALSE;
671
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200672 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100673 if (bufnrs == NULL)
674 return FALSE;
675
676 /* curbuf */
677 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100678
679 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100680 FOR_ALL_WINDOWS(wp)
681 if (wp->w_buffer != curbuf)
682 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
683
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100684 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +0200685 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100686 if (tp != curtab)
687 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
688 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100689
690 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +0200691 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100692 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
693
694 for (i = 0; i < bufnum; ++i)
695 {
696 buf = buflist_findnr(bufnrs[i]);
697 if (buf == NULL)
698 continue;
699 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
700 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200701 bufref_T bufref;
702
703 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100704#ifdef FEAT_TERMINAL
705 if (term_job_running(buf->b_term))
706 {
707 if (term_try_stop_job(buf) == FAIL)
708 break;
709 }
710 else
711#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100712 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +0200713 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100714 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
715 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200716 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100717 break; /* didn't save - still changes */
718 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 }
720
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100721 if (i >= bufnum)
722 goto theend;
723
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100724 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100725 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 exiting = FALSE;
727#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
728 /*
729 * When ":confirm" used, don't give an error message.
730 */
731 if (!(p_confirm || cmdmod.confirm))
732#endif
733 {
734 /* There must be a wait_return for this message, do_buffer()
735 * may cause a redraw. But wait_return() is a no-op when vgetc()
736 * is busy (Quit used from window menu), then make sure we don't
737 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +0000738 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 msg_row = cmdline_row;
741 msg_col = 0;
742 msg_didout = FALSE;
743 }
Bram Moolenaareb44a682017-08-03 22:44:55 +0200744 if (
745#ifdef FEAT_TERMINAL
746 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100747 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +0200748 buf->b_fname)
749 :
750#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100751 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200752 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 {
754 save = no_wait_return;
755 no_wait_return = FALSE;
756 wait_return(FALSE);
757 no_wait_return = save;
758 }
759 }
760
Bram Moolenaar071d4272004-06-13 20:20:40 +0000761 /* Try to find a window that contains the buffer. */
762 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100763 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 if (wp->w_buffer == buf)
765 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200766 bufref_T bufref;
767
768 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100769
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100770 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100771
Bram Moolenaarbdace832019-03-02 10:13:42 +0100772 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200773 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100774 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100775 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100777buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778
779 /* Open the changed buffer in the current window. */
780 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +0100781 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100783theend:
784 vim_free(bufnrs);
785 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786}
787
788/*
789 * return FAIL if there is no file name, OK if there is one
790 * give error message for FAIL
791 */
792 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100793check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794{
795 if (curbuf->b_ffname == NULL)
796 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100797 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798 return FAIL;
799 }
800 return OK;
801}
802
803/*
804 * flush the contents of a buffer, unless it has no file name
805 *
806 * return FAIL for failure, OK otherwise
807 */
808 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100809buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810{
811 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813
814 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
815 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
816 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000818 {
Bram Moolenaar8820b482017-03-16 17:23:31 +0100819 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +0100820 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000821 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 return retval;
823}
824
825/*
826 * Code to handle the argument list.
827 */
828
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200829static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100830static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200831static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000832#define AL_SET 1
833#define AL_ADD 2
834#define AL_DEL 3
835
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000837 * Isolate one argument, taking backticks.
838 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 * Return a pointer to the start of the next argument.
840 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000841 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100842do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843{
844 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845 int inbacktick;
846
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 inbacktick = FALSE;
848 for (p = str; *str; ++str)
849 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000850 /* When the backslash is used for escaping the special meaning of a
851 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852 if (rem_backslash(str))
853 {
854 *p++ = *str++;
855 *p++ = *str;
856 }
857 else
858 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000859 /* An item ends at a space not in backticks */
860 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000862 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000864 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 }
866 }
867 str = skipwhite(str);
868 *p = NUL;
869
870 return str;
871}
872
Bram Moolenaar86b68352004-12-27 21:59:20 +0000873/*
874 * Separate the arguments in "str" and return a list of pointers in the
875 * growarray "gap".
876 */
Bram Moolenaar398ee732017-08-03 14:29:14 +0200877 static int
878get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +0000879{
880 ga_init2(gap, (int)sizeof(char_u *), 20);
881 while (*str != NUL)
882 {
883 if (ga_grow(gap, 1) == FAIL)
884 {
885 ga_clear(gap);
886 return FAIL;
887 }
888 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
889
Bram Moolenaar398ee732017-08-03 14:29:14 +0200890 /* If str is escaped, don't handle backslashes or spaces */
891 if (!escaped)
892 return OK;
893
Bram Moolenaar86b68352004-12-27 21:59:20 +0000894 /* Isolate one argument, change it in-place, put a NUL after it. */
895 str = do_one_arg(str);
896 }
897 return OK;
898}
899
Bram Moolenaar7df351e2006-01-23 22:30:28 +0000900#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000901/*
902 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +0200903 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000904 * Return FAIL or OK.
905 */
906 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100907get_arglist_exp(
908 char_u *str,
909 int *fcountp,
910 char_u ***fnamesp,
911 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000912{
913 garray_T ga;
914 int i;
915
Bram Moolenaar398ee732017-08-03 14:29:14 +0200916 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000917 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +0200918 if (wig == TRUE)
919 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
920 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
921 else
922 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
923 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
924
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +0000925 ga_clear(&ga);
926 return i;
927}
928#endif
929
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930/*
931 * Redefine the argument list.
932 */
933 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100934set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935{
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200936 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000938
939/*
940 * "what" == AL_SET: Redefine the argument list to 'str'.
941 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
942 * "what" == AL_DEL: remove files in 'str' from the argument list.
943 *
944 * Return FAIL for failure, OK otherwise.
945 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100947do_arglist(
948 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +0100949 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +0200950 int after UNUSED, // 0 means before first one
951 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952{
953 garray_T new_ga;
954 int exp_count;
955 char_u **exp_files;
956 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000957 char_u *p;
958 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +0200959 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960
961 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +0100962 * Set default argument for ":argadd" command.
963 */
964 if (what == AL_ADD && *str == NUL)
965 {
966 if (curbuf->b_ffname == NULL)
967 return FAIL;
968 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +0200969 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +0100970 }
971
972 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000973 * Collect all file name arguments in "new_ga".
974 */
Bram Moolenaar398ee732017-08-03 14:29:14 +0200975 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +0000976 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000977
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978 if (what == AL_DEL)
979 {
980 regmatch_T regmatch;
981 int didone;
982
983 /*
984 * Delete the items: use each item as a regexp and find a match in the
985 * argument list.
986 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +0100987 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
989 {
990 p = ((char_u **)new_ga.ga_data)[i];
991 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
992 if (p == NULL)
993 break;
994 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
995 if (regmatch.regprog == NULL)
996 {
997 vim_free(p);
998 break;
999 }
1000
1001 didone = FALSE;
1002 for (match = 0; match < ARGCOUNT; ++match)
1003 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1004 (colnr_T)0))
1005 {
1006 didone = TRUE;
1007 vim_free(ARGLIST[match].ae_fname);
1008 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1009 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1010 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 if (curwin->w_arg_idx > match)
1012 --curwin->w_arg_idx;
1013 --match;
1014 }
1015
Bram Moolenaar473de612013-06-08 18:19:48 +02001016 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 vim_free(p);
1018 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001019 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020 }
1021 ga_clear(&new_ga);
1022 }
1023 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024 {
1025 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1026 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1027 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01001028 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001030 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031 return FAIL;
1032 }
1033
Bram Moolenaar071d4272004-06-13 20:20:40 +00001034 if (what == AL_ADD)
1035 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001036 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 vim_free(exp_files);
1038 }
1039 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001040 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001041 }
1042
1043 alist_check_arg_idx();
1044
1045 return OK;
1046}
1047
1048/*
1049 * Check the validity of the arg_idx for each other window.
1050 */
1051 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001052alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001055 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056
Bram Moolenaarf740b292006-02-16 22:11:02 +00001057 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 if (win->w_alist == curwin->w_alist)
1059 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060}
1061
1062/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001063 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001064 * index.
1065 */
1066 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001067editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001068{
1069 return !(win->w_arg_idx >= WARGCOUNT(win)
1070 || (win->w_buffer->b_fnum
1071 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1072 && (win->w_buffer->b_ffname == NULL
1073 || !(fullpathcmp(
1074 alist_name(&WARGLIST(win)[win->w_arg_idx]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001075 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))));
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001076}
1077
1078/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 * Check if window "win" is editing the w_arg_idx file in its argument list.
1080 */
1081 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001082check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001083{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001084 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085 {
1086 /* We are not editing the current entry in the argument list.
1087 * Set "arg_had_last" if we are editing the last one. */
1088 win->w_arg_idx_invalid = TRUE;
1089 if (win->w_arg_idx != WARGCOUNT(win) - 1
1090 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 && GARGCOUNT > 0
1093 && win->w_arg_idx < GARGCOUNT
1094 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1095 || (win->w_buffer->b_ffname != NULL
1096 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001097 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098 arg_had_last = TRUE;
1099 }
1100 else
1101 {
1102 /* We are editing the current entry in the argument list.
1103 * Set "arg_had_last" if it's also the last one */
1104 win->w_arg_idx_invalid = FALSE;
1105 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02001106 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 arg_had_last = TRUE;
1108 }
1109}
1110
1111/*
1112 * ":args", ":argslocal" and ":argsglobal".
1113 */
1114 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001115ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116{
1117 int i;
1118
1119 if (eap->cmdidx != CMD_args)
1120 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 alist_unlink(ALIST(curwin));
1122 if (eap->cmdidx == CMD_argglobal)
1123 ALIST(curwin) = &global_alist;
1124 else /* eap->cmdidx == CMD_arglocal */
1125 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 }
1127
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01001128 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 {
1130 /*
1131 * ":args file ..": define new argument list, handle like ":next"
1132 * Also for ":argslocal file .." and ":argsglobal file ..".
1133 */
1134 ex_next(eap);
1135 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001136 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137 {
1138 /*
1139 * ":args": list arguments.
1140 */
1141 if (ARGCOUNT > 0)
1142 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001143 char_u **items = ALLOC_MULT(char_u *, ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001144
1145 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001147 /* Overwrite the command, for a short list there is no
1148 * scrolling required and no wait_return(). */
1149 gotocmdline(TRUE);
1150
1151 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001152 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001153 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
1154 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 }
1156 }
1157 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158 else if (eap->cmdidx == CMD_arglocal)
1159 {
1160 garray_T *gap = &curwin->w_alist->al_ga;
1161
1162 /*
1163 * ":argslocal": make a local copy of the global argument list.
1164 */
1165 if (ga_grow(gap, GARGCOUNT) == OK)
1166 for (i = 0; i < GARGCOUNT; ++i)
1167 if (GARGLIST[i].ae_fname != NULL)
1168 {
1169 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1170 vim_strsave(GARGLIST[i].ae_fname);
1171 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1172 GARGLIST[i].ae_fnum;
1173 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001174 }
1175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176}
1177
1178/*
1179 * ":previous", ":sprevious", ":Next" and ":sNext".
1180 */
1181 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001182ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001183{
1184 /* If past the last one already, go to the last one. */
1185 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1186 do_argfile(eap, ARGCOUNT - 1);
1187 else
1188 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1189}
1190
1191/*
1192 * ":rewind", ":first", ":sfirst" and ":srewind".
1193 */
1194 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001195ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196{
1197 do_argfile(eap, 0);
1198}
1199
1200/*
1201 * ":last" and ":slast".
1202 */
1203 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001204ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205{
1206 do_argfile(eap, ARGCOUNT - 1);
1207}
1208
1209/*
1210 * ":argument" and ":sargument".
1211 */
1212 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001213ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001214{
1215 int i;
1216
1217 if (eap->addr_count > 0)
1218 i = eap->line2 - 1;
1219 else
1220 i = curwin->w_arg_idx;
1221 do_argfile(eap, i);
1222}
1223
1224/*
1225 * Edit file "argn" of the argument lists.
1226 */
1227 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001228do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229{
1230 int other;
1231 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001232 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233
Bram Moolenaar8cdbd5b2019-06-16 15:50:45 +02001234 if (ERROR_IF_POPUP_WINDOW)
Bram Moolenaar815b76b2019-06-01 14:15:52 +02001235 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236 if (argn < 0 || argn >= ARGCOUNT)
1237 {
1238 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001239 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001241 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001243 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 }
1245 else
1246 {
1247 setpcmark();
1248#ifdef FEAT_GUI
1249 need_mouse_correct = TRUE;
1250#endif
1251
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00001252 /* split window or create new tab page first */
1253 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 {
1255 if (win_split(0, 0) == FAIL)
1256 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001257 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 }
1259 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 {
1261 /*
1262 * if 'hidden' set, only check for changed file when re-editing
1263 * the same buffer
1264 */
1265 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02001266 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267 {
1268 p = fix_fname(alist_name(&ARGLIST[argn]));
1269 other = otherfile(p);
1270 vim_free(p);
1271 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001272 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001273 && check_changed(curbuf, CCGD_AW
1274 | (other ? 0 : CCGD_MULTWIN)
1275 | (eap->forceit ? CCGD_FORCEIT : 0)
1276 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277 return;
1278 }
1279
1280 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001281 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282 arg_had_last = TRUE;
1283
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001284 /* Edit the file; always use the last known line number.
1285 * When it fails (e.g. Abort for already edited file) restore the
1286 * argument index. */
1287 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02001289 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001290 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001291 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001293 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294 setmark('\'');
1295 }
1296}
1297
1298/*
1299 * ":next", and commands that behave like it.
1300 */
1301 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001302ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303{
1304 int i;
1305
1306 /*
1307 * check for changed buffer now, if this fails the argument list is not
1308 * redefined.
1309 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02001310 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001312 || !check_changed(curbuf, CCGD_AW
1313 | (eap->forceit ? CCGD_FORCEIT : 0)
1314 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 {
1316 if (*eap->arg != NUL) /* redefine file list */
1317 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001318 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319 return;
1320 i = 0;
1321 }
1322 else
1323 i = curwin->w_arg_idx + (int)eap->line2;
1324 do_argfile(eap, i);
1325 }
1326}
1327
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328/*
1329 * ":argedit"
1330 */
1331 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001332ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001333{
Bram Moolenaar90305c62017-07-16 15:31:17 +02001334 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001335 // Whether curbuf will be reused, curbuf->b_ffname will be set.
1336 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001337
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001338 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02001339 return;
1340#ifdef FEAT_TITLE
1341 maketitle();
1342#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001343
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001344 if (curwin->w_arg_idx == 0
1345 && (curbuf->b_ml.ml_flags & ML_EMPTY)
1346 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02001347 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001348 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02001349 if (i < ARGCOUNT)
1350 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001351}
1352
1353/*
1354 * ":argadd"
1355 */
1356 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001357ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001358{
1359 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001360 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
1361 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362#ifdef FEAT_TITLE
1363 maketitle();
1364#endif
1365}
1366
1367/*
1368 * ":argdelete"
1369 */
1370 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001371ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372{
1373 int i;
1374 int n;
1375
1376 if (eap->addr_count > 0)
1377 {
1378 /* ":1,4argdel": Delete all arguments in the range. */
1379 if (eap->line2 > ARGCOUNT)
1380 eap->line2 = ARGCOUNT;
1381 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01001382 if (*eap->arg != NUL)
1383 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001384 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01001385 else if (n <= 0)
1386 {
1387 /* Don't give an error for ":%argdel" if the list is empty. */
1388 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001389 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01001390 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001391 else
1392 {
1393 for (i = eap->line1; i <= eap->line2; ++i)
1394 vim_free(ARGLIST[i - 1].ae_fname);
1395 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
1396 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
1397 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 if (curwin->w_arg_idx >= eap->line2)
1399 curwin->w_arg_idx -= n;
1400 else if (curwin->w_arg_idx > eap->line1)
1401 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01001402 if (ARGCOUNT == 0)
1403 curwin->w_arg_idx = 0;
1404 else if (curwin->w_arg_idx >= ARGCOUNT)
1405 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001406 }
1407 }
1408 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001409 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001410 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001411 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001412#ifdef FEAT_TITLE
1413 maketitle();
1414#endif
1415}
1416
1417/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001418 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419 */
1420 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001421ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001422{
1423 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001424 win_T *wp;
1425 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01001426 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001428#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001430#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001431 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001432#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02001433 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001434 int qf_idx;
1435#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001436
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01001437#ifndef FEAT_QUICKFIX
1438 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
1439 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1440 {
1441 ex_ni(eap);
1442 return;
1443 }
1444#endif
1445
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001446#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001447 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001448 {
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00001449 /* Don't do syntax HL autocommands. Skipping the syntax file is a
1450 * great speed improvement. */
1451 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001452
1453 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1454 buf->b_flags &= ~BF_SYN_SET;
1455 buf = curbuf;
1456 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001458#ifdef FEAT_CLIPBOARD
1459 start_global_changes();
1460#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001461
1462 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001463 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02001464 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001465 || !check_changed(curbuf, CCGD_AW
1466 | (eap->forceit ? CCGD_FORCEIT : 0)
1467 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001470 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001471 wp = firstwin;
1472 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001473 switch (eap->cmdidx)
1474 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01001475 case CMD_windo:
1476 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
1477 i++;
1478 break;
1479 case CMD_tabdo:
1480 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
1481 i++;
1482 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001483 case CMD_argdo:
1484 i = eap->line1 - 1;
1485 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001486 default:
1487 break;
1488 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001489 /* set pcmark now */
1490 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001491 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01001492 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001493 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01001494 || !buf->b_p_bl); buf = buf->b_next)
1495 if (buf->b_fnum > eap->line2)
1496 {
1497 buf = NULL;
1498 break;
1499 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001500 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01001501 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001502 }
1503#ifdef FEAT_QUICKFIX
1504 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1505 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1506 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02001507 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001508 if (qf_size <= 0 || eap->line1 > qf_size)
1509 buf = NULL;
1510 else
1511 {
1512 ex_cc(eap);
1513
1514 buf = curbuf;
1515 i = eap->line1 - 1;
1516 if (eap->addr_count <= 0)
1517 /* default is all the quickfix/location list entries */
1518 eap->line2 = qf_size;
1519 }
1520 }
1521#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001522 else
1523 setpcmark();
1524 listcmd_busy = TRUE; /* avoids setting pcmark below */
1525
Bram Moolenaare25bb902015-02-27 20:33:37 +01001526 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 {
1528 if (eap->cmdidx == CMD_argdo)
1529 {
1530 /* go to argument "i" */
1531 if (i == ARGCOUNT)
1532 break;
1533 /* Don't call do_argfile() when already there, it will try
1534 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001535 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001536 {
1537 /* Clear 'shm' to avoid that the file message overwrites
1538 * any output from the command. */
1539 p_shm_save = vim_strsave(p_shm);
1540 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001542 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1543 vim_free(p_shm_save);
1544 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545 if (curwin->w_arg_idx != i)
1546 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548 else if (eap->cmdidx == CMD_windo)
1549 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001550 /* go to window "wp" */
1551 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001552 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001553 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00001554 if (curwin != wp)
1555 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001556 wp = curwin->w_next;
1557 }
1558 else if (eap->cmdidx == CMD_tabdo)
1559 {
1560 /* go to window "tp" */
1561 if (!valid_tabpage(tp))
1562 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02001563 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001564 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566 else if (eap->cmdidx == CMD_bufdo)
1567 {
1568 /* Remember the number of the next listed buffer, in case
1569 * ":bwipe" is used or autocommands do something strange. */
1570 next_fnum = -1;
1571 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
1572 if (buf->b_p_bl)
1573 {
1574 next_fnum = buf->b_fnum;
1575 break;
1576 }
1577 }
1578
Bram Moolenaara162bc52015-01-07 16:54:21 +01001579 ++i;
1580
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581 /* execute the command */
1582 do_cmdline(eap->arg, eap->getline, eap->cookie,
1583 DOCMD_VERBOSE + DOCMD_NOWAIT);
1584
1585 if (eap->cmdidx == CMD_bufdo)
1586 {
1587 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01001588 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 break;
1590 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001591 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592 if (buf->b_fnum == next_fnum)
1593 break;
1594 if (buf == NULL)
1595 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001596
1597 /* Go to the next buffer. Clear 'shm' to avoid that the file
1598 * message overwrites any output from the command. */
1599 p_shm_save = vim_strsave(p_shm);
1600 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001602 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1603 vim_free(p_shm_save);
1604
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001605 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 if (curbuf->b_fnum != next_fnum)
1607 break;
1608 }
1609
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001610#ifdef FEAT_QUICKFIX
1611 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1612 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1613 {
1614 if (i >= qf_size || i >= eap->line2)
1615 break;
1616
1617 qf_idx = qf_get_cur_idx(eap);
1618
1619 ex_cnext(eap);
1620
1621 /* If jumping to the next quickfix entry fails, quit here */
1622 if (qf_get_cur_idx(eap) == qf_idx)
1623 break;
1624 }
1625#endif
1626
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627 if (eap->cmdidx == CMD_windo)
1628 {
1629 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01001630
Bram Moolenaar071d4272004-06-13 20:20:40 +00001631 /* required when 'scrollbind' has been set */
1632 if (curwin->w_p_scb)
1633 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01001635
Bram Moolenaara162bc52015-01-07 16:54:21 +01001636 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
1637 if (i+1 > eap->line2)
1638 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001639 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
1640 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641 }
1642 listcmd_busy = FALSE;
1643 }
1644
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001645#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001646 if (save_ei != NULL)
1647 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001648 buf_T *bnext;
1649 aco_save_T aco;
1650
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001651 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001652
1653 for (buf = firstbuf; buf != NULL; buf = bnext)
1654 {
1655 bnext = buf->b_next;
1656 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
1657 {
1658 buf->b_flags &= ~BF_SYN_SET;
1659
1660 // buffer was opened while Syntax autocommands were disabled,
1661 // need to trigger them now.
1662 if (buf == curbuf)
1663 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001664 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001665 else
1666 {
1667 aucmd_prepbuf(&aco, buf);
1668 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
1669 buf->b_fname, TRUE, buf);
1670 aucmd_restbuf(&aco);
1671 }
1672
1673 // start over, in case autocommands messed things up.
1674 bnext = firstbuf;
1675 }
1676 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001679#ifdef FEAT_CLIPBOARD
1680 end_global_changes();
1681#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682}
1683
1684/*
1685 * Add files[count] to the arglist of the current window after arg "after".
1686 * The file names in files[count] must have been allocated and are taken over.
1687 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001689 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001690alist_add_list(
1691 int count,
1692 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001693 int after, // where to add: 0 = before first one
1694 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001695{
1696 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01001697 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698
1699 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
1700 {
1701 if (after < 0)
1702 after = 0;
1703 if (after > ARGCOUNT)
1704 after = ARGCOUNT;
1705 if (after < ARGCOUNT)
1706 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
1707 (ARGCOUNT - after) * sizeof(aentry_T));
1708 for (i = 0; i < count; ++i)
1709 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001710 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
1711
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001713 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 }
1715 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01001716 if (old_argcount > 0 && curwin->w_arg_idx >= after)
1717 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001718 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719 }
1720
1721 for (i = 0; i < count; ++i)
1722 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001723}
1724
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02001725#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1726/*
1727 * Function given to ExpandGeneric() to obtain the possible arguments of the
1728 * argedit and argdelete commands.
1729 */
1730 char_u *
1731get_arglist_name(expand_T *xp UNUSED, int idx)
1732{
1733 if (idx >= ARGCOUNT)
1734 return NULL;
1735
1736 return alist_name(&ARGLIST[idx]);
1737}
1738#endif
1739
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001740
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741#ifdef FEAT_EVAL
1742/*
1743 * ":compiler[!] {name}"
1744 */
1745 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001746ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747{
1748 char_u *buf;
1749 char_u *old_cur_comp = NULL;
1750 char_u *p;
1751
1752 if (*eap->arg == NUL)
1753 {
1754 /* List all compiler scripts. */
1755 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1756 /* ) keep the indenter happy... */
1757 }
1758 else
1759 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02001760 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 if (buf != NULL)
1762 {
1763 if (eap->forceit)
1764 {
1765 /* ":compiler! {name}" sets global options */
1766 do_cmdline_cmd((char_u *)
1767 "command -nargs=* CompilerSet set <args>");
1768 }
1769 else
1770 {
1771 /* ":compiler! {name}" sets local options.
1772 * To remain backwards compatible "current_compiler" is always
1773 * used. A user's compiler plugin may set it, the distributed
1774 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001775 * "b:current_compiler" and restore "current_compiler".
1776 * Explicitly prepend "g:" to make it work in a function. */
1777 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001778 if (old_cur_comp != NULL)
1779 old_cur_comp = vim_strsave(old_cur_comp);
1780 do_cmdline_cmd((char_u *)
1781 "command -nargs=* CompilerSet setlocal <args>");
1782 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001783 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00001784 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785
1786 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001787 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001788 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 vim_free(buf);
1790
1791 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1792
1793 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001794 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 if (p != NULL)
1796 set_internal_string_var((char_u *)"b:current_compiler", p);
1797
1798 /* Restore "current_compiler" for ":compiler {name}". */
1799 if (!eap->forceit)
1800 {
1801 if (old_cur_comp != NULL)
1802 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001803 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804 old_cur_comp);
1805 vim_free(old_cur_comp);
1806 }
1807 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001808 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809 }
1810 }
1811 }
1812}
1813#endif
1814
1815/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001816 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 */
1818 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001819ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001821 char_u *arg = eap->arg;
1822 char_u *p = skiptowhite(arg);
1823 int len = (int)(p - arg);
1824 int flags = eap->forceit ? DIP_ALL : 0;
1825
1826 if (STRNCMP(arg, "START", len) == 0)
1827 {
1828 flags += DIP_START + DIP_NORTP;
1829 arg = skipwhite(arg + len);
1830 }
1831 else if (STRNCMP(arg, "OPT", len) == 0)
1832 {
1833 flags += DIP_OPT + DIP_NORTP;
1834 arg = skipwhite(arg + len);
1835 }
1836 else if (STRNCMP(arg, "PACK", len) == 0)
1837 {
1838 flags += DIP_START + DIP_OPT + DIP_NORTP;
1839 arg = skipwhite(arg + len);
1840 }
1841 else if (STRNCMP(arg, "ALL", len) == 0)
1842 {
1843 flags += DIP_START + DIP_OPT;
1844 arg = skipwhite(arg + len);
1845 }
1846
1847 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848}
1849
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001851source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001853 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854}
1855
1856/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001857 * Find the file "name" in all directories in "path" and invoke
1858 * "callback(fname, cookie)".
1859 * "name" can contain wildcards.
1860 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
1861 * When "flags" has DIP_DIR: find directories instead of files.
1862 * When "flags" has DIP_ERR: give an error message if there is no match.
1863 *
1864 * return FAIL when no file could be sourced, OK otherwise.
1865 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01001866 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001867do_in_path(
1868 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001869 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01001870 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001871 void (*callback)(char_u *fname, void *ck),
1872 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873{
1874 char_u *rtp;
1875 char_u *np;
1876 char_u *buf;
1877 char_u *rtp_copy;
1878 char_u *tail;
1879 int num_files;
1880 char_u **files;
1881 int i;
1882 int did_one = FALSE;
1883#ifdef AMIGA
1884 struct Process *proc = (struct Process *)FindTask(0L);
1885 APTR save_winptr = proc->pr_WindowPtr;
1886
1887 /* Avoid a requester here for a volume that doesn't exist. */
1888 proc->pr_WindowPtr = (APTR)-1L;
1889#endif
1890
1891 /* Make a copy of 'runtimepath'. Invoking the callback may change the
1892 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001893 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 buf = alloc(MAXPATHL);
1895 if (buf != NULL && rtp_copy != NULL)
1896 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001897 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001898 {
1899 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001900 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001901 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001902 verbose_leave();
1903 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001904
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 /* Loop over all entries in 'runtimepath'. */
1906 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01001907 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02001909 size_t buflen;
1910
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911 /* Copy the path from 'runtimepath' to buf[]. */
1912 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02001913 buflen = STRLEN(buf);
1914
1915 /* Skip after or non-after directories. */
1916 if (flags & (DIP_NOAFTER | DIP_AFTER))
1917 {
1918 int is_after = buflen >= 5
1919 && STRCMP(buf + buflen - 5, "after") == 0;
1920
1921 if ((is_after && (flags & DIP_NOAFTER))
1922 || (!is_after && (flags & DIP_AFTER)))
1923 continue;
1924 }
1925
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001926 if (name == NULL)
1927 {
1928 (*callback)(buf, (void *) &cookie);
1929 if (!did_one)
1930 did_one = (cookie == NULL);
1931 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02001932 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 {
1934 add_pathsep(buf);
1935 tail = buf + STRLEN(buf);
1936
1937 /* Loop over all patterns in "name" */
1938 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01001939 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 {
1941 /* Append the pattern from "name" to buf[]. */
1942 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
1943 "\t ");
1944
1945 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001946 {
1947 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001948 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001949 verbose_leave();
1950 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951
1952 /* Expand wildcards, invoke the callback for each match. */
1953 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01001954 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955 {
1956 for (i = 0; i < num_files; ++i)
1957 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001958 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01001960 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961 break;
1962 }
1963 FreeWild(num_files, files);
1964 }
1965 }
1966 }
1967 }
1968 }
1969 vim_free(buf);
1970 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001971 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001972 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001973 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
1974
1975 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001976 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001977 else if (p_verbose > 0)
1978 {
1979 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001980 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001981 verbose_leave();
1982 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001983 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984
1985#ifdef AMIGA
1986 proc->pr_WindowPtr = save_winptr;
1987#endif
1988
1989 return did_one ? OK : FAIL;
1990}
1991
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001992/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001993 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001994 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001995 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
1996 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001997 * Returns OK when at least one match found, FAIL otherwise.
1998 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001999 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002000 * passed by reference in this case, setting it to NULL indicates that callback
2001 * has done its job.
2002 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002003 static int
2004do_in_path_and_pp(
2005 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002006 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002007 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002008 void (*callback)(char_u *fname, void *ck),
2009 void *cookie)
2010{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002011 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002012 char_u *s;
2013 int len;
2014 char *start_dir = "pack/*/start/*/%s";
2015 char *opt_dir = "pack/*/opt/*/%s";
2016
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002017 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002018 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002019
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002020 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002021 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002022 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002023 s = alloc(len);
2024 if (s == NULL)
2025 return FAIL;
2026 vim_snprintf((char *)s, len, start_dir, name);
2027 done = do_in_path(p_pp, s, flags, callback, cookie);
2028 vim_free(s);
2029 }
2030
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002031 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002032 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002033 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002034 s = alloc(len);
2035 if (s == NULL)
2036 return FAIL;
2037 vim_snprintf((char *)s, len, opt_dir, name);
2038 done = do_in_path(p_pp, s, flags, callback, cookie);
2039 vim_free(s);
2040 }
2041
2042 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002043}
2044
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002045/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002046 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2047 */
2048 int
2049do_in_runtimepath(
2050 char_u *name,
2051 int flags,
2052 void (*callback)(char_u *fname, void *ck),
2053 void *cookie)
2054{
2055 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2056}
2057
2058/*
2059 * Source the file "name" from all directories in 'runtimepath'.
2060 * "name" can contain wildcards.
2061 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2062 *
2063 * return FAIL when no file could be sourced, OK otherwise.
2064 */
2065 int
2066source_runtime(char_u *name, int flags)
2067{
2068 return source_in_path(p_rtp, name, flags);
2069}
2070
2071/*
2072 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2073 */
2074 int
2075source_in_path(char_u *path, char_u *name, int flags)
2076{
2077 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2078}
2079
2080
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002081#if defined(FEAT_EVAL) || defined(PROTO)
2082
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002083/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002084 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002085 */
2086 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002087source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002088{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002089 int num_files;
2090 char_u **files;
2091 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002092
Bram Moolenaarf3654822016-03-04 22:12:23 +01002093 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002094 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002095 for (i = 0; i < num_files; ++i)
2096 (void)do_source(files[i], FALSE, DOSO_NONE);
2097 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002098 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002099}
2100
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002101/*
2102 * Add the package directory to 'runtimepath'.
2103 */
2104 static int
2105add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002106{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002107 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002108 char_u *entry;
2109 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002110 int c;
2111 char_u *new_rtp;
2112 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002113 size_t oldlen;
2114 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002115 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002116 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002117 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002118 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002119 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002120 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002121 char_u *buf = NULL;
2122 char_u *rtp_ffname;
2123 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002124 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002125
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002126 p4 = p3 = p2 = p1 = get_past_head(fname);
2127 for (p = p1; *p; MB_PTR_ADV(p))
2128 if (vim_ispathsep_nocolon(*p))
2129 {
2130 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2131 }
2132
2133 /* now we have:
2134 * rtp/pack/name/start/name
2135 * p4 p3 p2 p1
2136 *
2137 * find the part up to "pack" in 'runtimepath' */
2138 c = *++p4; /* append pathsep in order to expand symlink */
2139 *p4 = NUL;
2140 ffname = fix_fname(fname);
2141 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002142 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002143 return FAIL;
2144
Bram Moolenaar99396d42018-09-08 18:21:16 +02002145 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2146 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002147 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002148 buf = alloc(MAXPATHL);
2149 if (buf == NULL)
2150 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002151 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002152 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002153 char_u *cur_entry = entry;
2154
2155 copy_option_part(&entry, buf, MAXPATHL, ",");
2156 if (insp == NULL)
2157 {
2158 add_pathsep(buf);
2159 rtp_ffname = fix_fname(buf);
2160 if (rtp_ffname == NULL)
2161 goto theend;
2162 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2163 vim_free(rtp_ffname);
2164 if (match)
2165 // Insert "ffname" after this entry (and comma).
2166 insp = entry;
2167 }
2168
2169 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2170 && p > buf
2171 && vim_ispathsep(p[-1])
2172 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2173 {
2174 if (insp == NULL)
2175 // Did not find "ffname" before the first "after" directory,
2176 // insert it before this entry.
2177 insp = cur_entry;
2178 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002179 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002180 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002181 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002182
Bram Moolenaar99396d42018-09-08 18:21:16 +02002183 if (insp == NULL)
2184 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002185 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002186
Bram Moolenaar99396d42018-09-08 18:21:16 +02002187 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002188 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2189 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002190 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002191
2192 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002193 addlen = STRLEN(fname) + 1; // add one for comma
Bram Moolenaar51e14382019-05-25 20:21:28 +02002194 new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002195 if (new_rtp == NULL)
2196 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002197
2198 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2199 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002200 keep = (int)(insp - p_rtp);
2201 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002202 new_rtp_len = keep;
2203 if (*insp == NUL)
2204 new_rtp[new_rtp_len++] = ','; // add comma before
2205 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2206 new_rtp_len += addlen - 1;
2207 if (*insp != NUL)
2208 new_rtp[new_rtp_len++] = ','; // add comma after
2209
2210 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002211 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002212 int keep_after = (int)(after_insp - p_rtp);
2213
2214 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2215 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2216 keep_after - keep);
2217 new_rtp_len += keep_after - keep;
2218 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2219 new_rtp_len += afterlen - 1;
2220 new_rtp[new_rtp_len++] = ',';
2221 keep = keep_after;
2222 }
2223
2224 if (p_rtp[keep] != NUL)
2225 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2226 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2227 else
2228 new_rtp[new_rtp_len] = NUL;
2229
2230 if (afterlen > 0 && after_insp == NULL)
2231 {
2232 // Append afterdir when "after" was not found:
2233 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002234 STRCAT(new_rtp, ",");
2235 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002236 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002237
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002238 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2239 vim_free(new_rtp);
2240 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002241
2242theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002243 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002244 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002245 vim_free(afterdir);
2246 return retval;
2247}
2248
2249/*
2250 * Load scripts in "plugin" and "ftdetect" directories of the package.
2251 */
2252 static int
2253load_pack_plugin(char_u *fname)
2254{
2255 static char *plugpat = "%s/plugin/**/*.vim";
2256 static char *ftpat = "%s/ftdetect/*.vim";
2257 int len;
2258 char_u *ffname = fix_fname(fname);
2259 char_u *pat = NULL;
2260 int retval = FAIL;
2261
2262 if (ffname == NULL)
2263 return FAIL;
2264 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2265 pat = alloc(len);
2266 if (pat == NULL)
2267 goto theend;
2268 vim_snprintf((char *)pat, len, plugpat, ffname);
2269 source_all_matches(pat);
2270
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002271 {
2272 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2273
2274 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2275 * found when it loads. */
2276 if (cmd != NULL && eval_to_number(cmd) > 0)
2277 {
2278 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2279 vim_snprintf((char *)pat, len, ftpat, ffname);
2280 source_all_matches(pat);
2281 do_cmdline_cmd((char_u *)"augroup END");
2282 }
2283 vim_free(cmd);
2284 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002285 vim_free(pat);
2286 retval = OK;
2287
2288theend:
2289 vim_free(ffname);
2290 return retval;
2291}
2292
2293/* used for "cookie" of add_pack_plugin() */
2294static int APP_ADD_DIR;
2295static int APP_LOAD;
2296static int APP_BOTH;
2297
2298 static void
2299add_pack_plugin(char_u *fname, void *cookie)
2300{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002301 if (cookie != &APP_LOAD)
2302 {
2303 char_u *buf = alloc(MAXPATHL);
2304 char_u *p;
2305 int found = FALSE;
2306
2307 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002308 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002309 p = p_rtp;
2310 while (*p != NUL)
2311 {
2312 copy_option_part(&p, buf, MAXPATHL, ",");
2313 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2314 {
2315 found = TRUE;
2316 break;
2317 }
2318 }
2319 vim_free(buf);
2320 if (!found)
2321 /* directory is not yet in 'runtimepath', add it */
2322 if (add_pack_dir_to_rtp(fname) == FAIL)
2323 return;
2324 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002325
2326 if (cookie != &APP_ADD_DIR)
2327 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002328}
2329
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002330/*
2331 * Add all packages in the "start" directory to 'runtimepath'.
2332 */
2333 void
2334add_pack_start_dirs(void)
2335{
2336 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2337 add_pack_plugin, &APP_ADD_DIR);
2338}
2339
2340/*
2341 * Load plugins from all packages in the "start" directory.
2342 */
2343 void
2344load_start_packages(void)
2345{
2346 did_source_packages = TRUE;
2347 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2348 add_pack_plugin, &APP_LOAD);
2349}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002350
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002351/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002352 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002353 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002354 */
2355 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002356ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002357{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002358 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002359 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002360 /* First do a round to add all directories to 'runtimepath', then load
2361 * the plugins. This allows for plugins to use an autoload directory
2362 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002363 add_pack_start_dirs();
2364 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002365 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002366}
2367
2368/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002369 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002370 */
2371 void
2372ex_packadd(exarg_T *eap)
2373{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002374 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002375 int len;
2376 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002377 int round;
2378 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002379
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002380 /* Round 1: use "start", round 2: use "opt". */
2381 for (round = 1; round <= 2; ++round)
2382 {
2383 /* Only look under "start" when loading packages wasn't done yet. */
2384 if (round == 1 && did_source_packages)
2385 continue;
2386
2387 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002388 pat = alloc(len);
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002389 if (pat == NULL)
2390 return;
2391 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
2392 /* The first round don't give a "not found" error, in the second round
2393 * only when nothing was found in the first round. */
2394 res = do_in_path(p_pp, (char_u *)pat,
2395 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
2396 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
2397 vim_free(pat);
2398 }
Bram Moolenaar91715872016-03-03 17:13:03 +01002399}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002400#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01002401
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002402#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002403/*
2404 * ":options"
2405 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002407ex_options(
2408 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409{
Bram Moolenaare0b59492019-05-21 20:54:45 +02002410 vim_setenv((char_u *)"OPTWIN_CMD",
2411 (char_u *)(cmdmod.tab ? "tab"
2412 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2414}
2415#endif
2416
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002417#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
2418
2419# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
2420/*
2421 * Detect Python 3 or 2, and initialize 'pyxversion'.
2422 */
2423 void
2424init_pyxversion(void)
2425{
2426 if (p_pyx == 0)
2427 {
2428 if (python3_enabled(FALSE))
2429 p_pyx = 3;
2430 else if (python_enabled(FALSE))
2431 p_pyx = 2;
2432 }
2433}
2434# endif
2435
2436/*
2437 * Does a file contain one of the following strings at the beginning of any
2438 * line?
2439 * "#!(any string)python2" => returns 2
2440 * "#!(any string)python3" => returns 3
2441 * "# requires python 2.x" => returns 2
2442 * "# requires python 3.x" => returns 3
2443 * otherwise return 0.
2444 */
2445 static int
2446requires_py_version(char_u *filename)
2447{
2448 FILE *file;
2449 int requires_py_version = 0;
2450 int i, lines;
2451
2452 lines = (int)p_mls;
2453 if (lines < 0)
2454 lines = 5;
2455
2456 file = mch_fopen((char *)filename, "r");
2457 if (file != NULL)
2458 {
2459 for (i = 0; i < lines; i++)
2460 {
2461 if (vim_fgets(IObuff, IOSIZE, file))
2462 break;
2463 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
2464 {
2465 /* Check shebang. */
2466 if (strstr((char *)IObuff + 2, "python2") != NULL)
2467 {
2468 requires_py_version = 2;
2469 break;
2470 }
2471 if (strstr((char *)IObuff + 2, "python3") != NULL)
2472 {
2473 requires_py_version = 3;
2474 break;
2475 }
2476 }
2477 IObuff[21] = '\0';
2478 if (STRCMP("# requires python 2.x", IObuff) == 0)
2479 {
2480 requires_py_version = 2;
2481 break;
2482 }
2483 if (STRCMP("# requires python 3.x", IObuff) == 0)
2484 {
2485 requires_py_version = 3;
2486 break;
2487 }
2488 }
2489 fclose(file);
2490 }
2491 return requires_py_version;
2492}
2493
2494
2495/*
2496 * Source a python file using the requested python version.
2497 */
2498 static void
2499source_pyx_file(exarg_T *eap, char_u *fname)
2500{
2501 exarg_T ex;
2502 int v = requires_py_version(fname);
2503
2504# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2505 init_pyxversion();
2506# endif
2507 if (v == 0)
2508 {
2509# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2510 /* user didn't choose a preference, 'pyx' is used */
2511 v = p_pyx;
2512# elif defined(FEAT_PYTHON)
2513 v = 2;
2514# elif defined(FEAT_PYTHON3)
2515 v = 3;
2516# endif
2517 }
2518
2519 /*
2520 * now source, if required python version is not supported show
2521 * unobtrusive message.
2522 */
2523 if (eap == NULL)
2524 vim_memset(&ex, 0, sizeof(ex));
2525 else
2526 ex = *eap;
2527 ex.arg = fname;
2528 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
2529
2530 if (v == 2)
2531 {
2532# ifdef FEAT_PYTHON
2533 ex_pyfile(&ex);
2534# else
2535 vim_snprintf((char *)IObuff, IOSIZE,
2536 _("W20: Required python version 2.x not supported, ignoring file: %s"),
2537 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002538 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002539# endif
2540 return;
2541 }
2542 else
2543 {
2544# ifdef FEAT_PYTHON3
2545 ex_py3file(&ex);
2546# else
2547 vim_snprintf((char *)IObuff, IOSIZE,
2548 _("W21: Required python version 3.x not supported, ignoring file: %s"),
2549 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002550 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01002551# endif
2552 return;
2553 }
2554}
2555
2556/*
2557 * ":pyxfile {fname}"
2558 */
2559 void
2560ex_pyxfile(exarg_T *eap)
2561{
2562 source_pyx_file(eap, eap->arg);
2563}
2564
2565/*
2566 * ":pyx"
2567 */
2568 void
2569ex_pyx(exarg_T *eap)
2570{
2571# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2572 init_pyxversion();
2573 if (p_pyx == 2)
2574 ex_python(eap);
2575 else
2576 ex_py3(eap);
2577# elif defined(FEAT_PYTHON)
2578 ex_python(eap);
2579# elif defined(FEAT_PYTHON3)
2580 ex_py3(eap);
2581# endif
2582}
2583
2584/*
2585 * ":pyxdo"
2586 */
2587 void
2588ex_pyxdo(exarg_T *eap)
2589{
2590# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
2591 init_pyxversion();
2592 if (p_pyx == 2)
2593 ex_pydo(eap);
2594 else
2595 ex_py3do(eap);
2596# elif defined(FEAT_PYTHON)
2597 ex_pydo(eap);
2598# elif defined(FEAT_PYTHON3)
2599 ex_py3do(eap);
2600# endif
2601}
2602
2603#endif
2604
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605/*
2606 * ":source {fname}"
2607 */
2608 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002609ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610{
2611#ifdef FEAT_BROWSE
2612 if (cmdmod.browse)
2613 {
2614 char_u *fname = NULL;
2615
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002616 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02002617 NULL, NULL,
2618 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619 if (fname != NULL)
2620 {
2621 cmd_source(fname, eap);
2622 vim_free(fname);
2623 }
2624 }
2625 else
2626#endif
2627 cmd_source(eap->arg, eap);
2628}
2629
2630 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002631cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632{
2633 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002634 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002637 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002638 * Need to execute the commands directly. This is required at least
2639 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640 * - ":g" command busy
2641 * - after ":argdo", ":windo" or ":bufdo"
2642 * - another command follows
2643 * - inside a loop
2644 */
2645 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2646#ifdef FEAT_EVAL
2647 || eap->cstack->cs_idx >= 0
2648#endif
2649 );
2650
2651 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002652 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002653 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654}
2655
2656/*
2657 * ":source" and associated commands.
2658 */
2659/*
2660 * Structure used to store info for each sourced file.
2661 * It is shared between do_source() and getsourceline().
2662 * This is required, because it needs to be handed to do_cmdline() and
2663 * sourcing can be done recursively.
2664 */
2665struct source_cookie
2666{
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002667 FILE *fp; // opened file for sourcing
2668 char_u *nextline; // if not NULL: line that was read ahead
2669 linenr_T sourcing_lnum; // line number of the source file
2670 int finished; // ":finish" used
Bram Moolenaar00590742019-02-15 21:06:09 +01002671#ifdef USE_CRNL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002672 int fileformat; // EOL_UNKNOWN, EOL_UNIX or EOL_DOS
2673 int error; // TRUE if LF found after CR-LF
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674#endif
2675#ifdef FEAT_EVAL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002676 linenr_T breakpoint; // next line with breakpoint or zero
2677 char_u *fname; // name of sourced file
2678 int dbg_tick; // debug_tick when breakpoint was set
2679 int level; // top nesting level of sourced file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002681 vimconv_T conv; // type of conversion
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682};
2683
2684#ifdef FEAT_EVAL
2685/*
2686 * Return the address holding the next breakpoint line for a source cookie.
2687 */
2688 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002689source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690{
2691 return &((struct source_cookie *)cookie)->breakpoint;
2692}
2693
2694/*
2695 * Return the address holding the debug tick for a source cookie.
2696 */
2697 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002698source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002699{
2700 return &((struct source_cookie *)cookie)->dbg_tick;
2701}
2702
2703/*
2704 * Return the nesting level for a source cookie.
2705 */
2706 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002707source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708{
2709 return ((struct source_cookie *)cookie)->level;
2710}
2711#endif
2712
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002713static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714
Bram Moolenaar4f974752019-02-17 17:44:42 +01002715#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002716# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717/*
2718 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002719 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 */
2721 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002722fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723{
Bram Moolenaar4f974752019-02-17 17:44:42 +01002724# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002725 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2726# else
2727 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002728# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729
2730 if (fd_tmp == -1)
2731 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002732
2733# ifdef HAVE_FD_CLOEXEC
2734 {
2735 int fdflags = fcntl(fd_tmp, F_GETFD);
2736 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02002737 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002738 }
2739# endif
2740
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741 return fdopen(fd_tmp, READBIN);
2742}
2743#endif
2744
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745/*
2746 * do_source: Read the file "fname" and execute its lines as EX commands.
2747 *
2748 * This function may be called recursively!
2749 *
2750 * return FAIL if file could not be opened, OK otherwise
2751 */
2752 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002753do_source(
2754 char_u *fname,
2755 int check_other, /* check for .vimrc and _vimrc */
2756 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757{
2758 struct source_cookie cookie;
2759 char_u *save_sourcing_name;
2760 linenr_T save_sourcing_lnum;
2761 char_u *p;
2762 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002763 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 int retval = FAIL;
2765#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002766 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002768 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002769 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002771 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02002773 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774 int stat_ok;
2775# endif
2776#endif
2777#ifdef STARTUPTIME
2778 struct timeval tv_rel;
2779 struct timeval tv_start;
2780#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002781#ifdef FEAT_PROFILE
2782 proftime_T wait_start;
2783#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002784 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787 if (p == NULL)
2788 return retval;
2789 fname_exp = fix_fname(p);
2790 vim_free(p);
2791 if (fname_exp == NULL)
2792 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002793 if (mch_isdir(fname_exp))
2794 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002795 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796 goto theend;
2797 }
2798
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002799 /* Apply SourceCmd autocommands, they should get the file and source it. */
2800 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2801 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2802 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002803 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002804#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002805 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002806#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002807 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002808#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002809 if (retval == OK)
2810 // Apply SourcePost autocommands.
2811 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
2812 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002813 goto theend;
2814 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002815
2816 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002817 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002818
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002819#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2821#else
2822 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2823#endif
2824 if (cookie.fp == NULL && check_other)
2825 {
2826 /*
2827 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2828 * and ".exrc" by "_exrc" or vice versa.
2829 */
2830 p = gettail(fname_exp);
2831 if ((*p == '.' || *p == '_')
2832 && (STRICMP(p + 1, "vimrc") == 0
2833 || STRICMP(p + 1, "gvimrc") == 0
2834 || STRICMP(p + 1, "exrc") == 0))
2835 {
2836 if (*p == '_')
2837 *p = '.';
2838 else
2839 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002840#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2842#else
2843 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2844#endif
2845 }
2846 }
2847
2848 if (cookie.fp == NULL)
2849 {
2850 if (p_verbose > 0)
2851 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002852 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002854 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002856 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002857 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002858 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859 }
2860 goto theend;
2861 }
2862
2863 /*
2864 * The file exists.
2865 * - In verbose mode, give a message.
2866 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2867 */
2868 if (p_verbose > 1)
2869 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002870 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002872 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002874 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002875 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002876 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002878 if (is_vimrc == DOSO_VIMRC)
2879 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2880 else if (is_vimrc == DOSO_GVIMRC)
2881 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882
2883#ifdef USE_CRNL
2884 /* If no automatic file format: Set default to CR-NL. */
2885 if (*p_ffs == NUL)
2886 cookie.fileformat = EOL_DOS;
2887 else
2888 cookie.fileformat = EOL_UNKNOWN;
2889 cookie.error = FALSE;
2890#endif
2891
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 cookie.nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002893 cookie.sourcing_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894 cookie.finished = FALSE;
2895
2896#ifdef FEAT_EVAL
2897 /*
2898 * Check if this script has a breakpoint.
2899 */
2900 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2901 cookie.fname = fname_exp;
2902 cookie.dbg_tick = debug_tick;
2903
2904 cookie.level = ex_nesting_level;
2905#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906
2907 /*
2908 * Keep the sourcing name/lnum, for recursive calls.
2909 */
2910 save_sourcing_name = sourcing_name;
2911 sourcing_name = fname_exp;
2912 save_sourcing_lnum = sourcing_lnum;
2913 sourcing_lnum = 0;
2914
2915#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01002916 if (time_fd != NULL)
2917 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918#endif
2919
2920#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00002921# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002922 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002923 prof_child_enter(&wait_start); /* entering a child now */
2924# endif
2925
2926 /* Don't use local function variables, if called from a function.
2927 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002928 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002929
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002930 save_current_sctx = current_sctx;
2931 current_sctx.sc_lnum = 0;
2932 current_sctx.sc_version = 1;
2933
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002934 // Check if this script was sourced before to finds its SID.
2935 // If it's new, generate a new SID.
2936 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002937 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938# ifdef UNIX
2939 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2940# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002941 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
2942 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002943 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002944 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002945 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 && (
2947# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00002948 /* Compare dev/ino when possible, it catches symbolic
2949 * links. Also compare file names, the inode may change
2950 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002951 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002952 && (si->sn_dev == st.st_dev
2953 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002955 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002957 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002958 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002960 current_sctx.sc_sid = ++last_current_SID;
2961 if (ga_grow(&script_items,
2962 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002963 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002964 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002966 ++script_items.ga_len;
2967 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
2968# ifdef FEAT_PROFILE
2969 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002970# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002972 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002973 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01002974 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00002975# ifdef UNIX
2976 if (stat_ok)
2977 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002978 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002979 si->sn_dev = st.st_dev;
2980 si->sn_ino = st.st_ino;
2981 }
2982 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002983 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002984# endif
2985
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002987 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002988 }
2989
Bram Moolenaar05159a02005-02-26 23:04:13 +00002990# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002991 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002992 {
2993 int forceit;
2994
2995 /* Check if we do profiling for this script. */
2996 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
2997 {
2998 script_do_profile(si);
2999 si->sn_pr_force = forceit;
3000 }
3001 if (si->sn_prof_on)
3002 {
3003 ++si->sn_pr_count;
3004 profile_start(&si->sn_pr_start);
3005 profile_zero(&si->sn_pr_children);
3006 }
3007 }
3008# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009#endif
3010
Bram Moolenaar67435d92017-10-19 21:04:37 +02003011 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3012
3013 /* Read the first line so we can check for a UTF-8 BOM. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02003014 firstline = getsourceline(0, (void *)&cookie, 0, TRUE);
Bram Moolenaar67435d92017-10-19 21:04:37 +02003015 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3016 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3017 {
3018 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3019 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3020 p = string_convert(&cookie.conv, firstline + 3, NULL);
3021 if (p == NULL)
3022 p = vim_strsave(firstline + 3);
3023 if (p != NULL)
3024 {
3025 vim_free(firstline);
3026 firstline = p;
3027 }
3028 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02003029
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 /*
3031 * Call do_cmdline, which will call getsourceline() to get the lines.
3032 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003033 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003036
3037#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003038 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003039 {
3040 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003041 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003042 if (si->sn_prof_on)
3043 {
3044 profile_end(&si->sn_pr_start);
3045 profile_sub_wait(&wait_start, &si->sn_pr_start);
3046 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003047 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3048 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003049 }
3050 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051#endif
3052
3053 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003054 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055 sourcing_name = save_sourcing_name;
3056 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 if (p_verbose > 1)
3058 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003059 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003060 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003062 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003063 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064 }
3065#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003066 if (time_fd != NULL)
3067 {
3068 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3069 time_msg((char *)IObuff, &tv_start);
3070 time_pop(&tv_rel);
3071 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072#endif
3073
Bram Moolenaar2b618522019-01-12 13:26:03 +01003074 if (!got_int)
3075 trigger_source_post = TRUE;
3076
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077#ifdef FEAT_EVAL
3078 /*
3079 * After a "finish" in debug mode, need to break at first command of next
3080 * sourced file.
3081 */
3082 if (save_debug_break_level > ex_nesting_level
3083 && debug_break_level == ex_nesting_level)
3084 ++debug_break_level;
3085#endif
3086
Bram Moolenaar05159a02005-02-26 23:04:13 +00003087#ifdef FEAT_EVAL
3088almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003089 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003090 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003091# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003092 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003093 prof_child_exit(&wait_start); /* leaving a child now */
3094# endif
3095#endif
3096 fclose(cookie.fp);
3097 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003098 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003099 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003100
Bram Moolenaar2b618522019-01-12 13:26:03 +01003101 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003102 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003103
Bram Moolenaar071d4272004-06-13 20:20:40 +00003104theend:
3105 vim_free(fname_exp);
3106 return retval;
3107}
3108
3109#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003110
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111/*
3112 * ":scriptnames"
3113 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003115ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116{
3117 int i;
3118
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003119 if (eap->addr_count > 0)
3120 {
3121 // :script {scriptId}: edit the script
3122 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003123 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003124 else
3125 {
3126 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3127 do_exedit(eap, NULL);
3128 }
3129 return;
3130 }
3131
Bram Moolenaar05159a02005-02-26 23:04:13 +00003132 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3133 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003134 {
3135 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3136 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003137 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003138 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139}
3140
3141# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3142/*
3143 * Fix slashes in the list of script names for 'shellslash'.
3144 */
3145 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003146scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147{
3148 int i;
3149
Bram Moolenaar05159a02005-02-26 23:04:13 +00003150 for (i = 1; i <= script_items.ga_len; ++i)
3151 if (SCRIPT_ITEM(i).sn_name != NULL)
3152 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153}
3154# endif
3155
3156/*
3157 * Get a pointer to a script name. Used for ":verbose set".
3158 */
3159 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003160get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003161{
3162 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003163 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003165 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003166 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003167 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003169 return (char_u *)_("environment variable");
3170 if (id == SID_ERROR)
3171 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003172 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003173}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003174
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003175# if defined(EXITFREE) || defined(PROTO)
3176 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003177free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003178{
3179 int i;
3180
3181 for (i = script_items.ga_len; i > 0; --i)
3182 vim_free(SCRIPT_ITEM(i).sn_name);
3183 ga_clear(&script_items);
3184}
3185# endif
3186
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187#endif
3188
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003189 linenr_T
3190get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), void *cookie)
3191{
3192 return fgetline == getsourceline
3193 ? ((struct source_cookie *)cookie)->sourcing_lnum
3194 : sourcing_lnum;
3195}
3196
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197/*
3198 * Get one full line from a sourced file.
3199 * Called by do_cmdline() when it's called from do_source().
3200 *
3201 * Return a pointer to the line in allocated memory.
3202 * Return NULL for end-of-file or some error.
3203 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 char_u *
Bram Moolenaare96a2492019-06-25 04:12:16 +02003205getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206{
3207 struct source_cookie *sp = (struct source_cookie *)cookie;
3208 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003209 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210
3211#ifdef FEAT_EVAL
3212 /* If breakpoints have been added/deleted need to check for it. */
3213 if (sp->dbg_tick < debug_tick)
3214 {
3215 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3216 sp->dbg_tick = debug_tick;
3217 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003218# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003219 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003220 script_line_end();
3221# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003222#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003223
3224 // Set the current sourcing line number.
3225 sourcing_lnum = sp->sourcing_lnum + 1;
3226
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 /*
3228 * Get current line. If there is a read-ahead line, use it, otherwise get
3229 * one now.
3230 */
3231 if (sp->finished)
3232 line = NULL;
3233 else if (sp->nextline == NULL)
3234 line = get_one_sourceline(sp);
3235 else
3236 {
3237 line = sp->nextline;
3238 sp->nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003239 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003241#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003242 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003243 script_line_start();
3244#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245
3246 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3247 * contain the 'C' flag. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02003248 if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249 {
3250 /* compensate for the one line read-ahead */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003251 --sp->sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003252
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003253 // Get the next line and concatenate it when it starts with a
3254 // backslash. We always need to read the next line, keep it in
3255 // sp->nextline.
3256 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003257 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003258 if (sp->nextline != NULL
3259 && (*(p = skipwhite(sp->nextline)) == '\\'
3260 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003262 garray_T ga;
3263
Bram Moolenaarb549a732012-02-22 18:29:33 +01003264 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003265 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003266 if (*p == '\\')
3267 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003268 for (;;)
3269 {
3270 vim_free(sp->nextline);
3271 sp->nextline = get_one_sourceline(sp);
3272 if (sp->nextline == NULL)
3273 break;
3274 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003275 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003276 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003277 // Adjust the growsize to the current length to speed up
3278 // concatenating many lines.
3279 if (ga.ga_len > 400)
3280 {
3281 if (ga.ga_len > 8000)
3282 ga.ga_growsize = 8000;
3283 else
3284 ga.ga_growsize = ga.ga_len;
3285 }
3286 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003287 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003288 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3289 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003290 }
3291 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003293 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294 }
3295 }
3296
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3298 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003299 char_u *s;
3300
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 /* Convert the encoding of the script line. */
3302 s = string_convert(&sp->conv, line, NULL);
3303 if (s != NULL)
3304 {
3305 vim_free(line);
3306 line = s;
3307 }
3308 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309
3310#ifdef FEAT_EVAL
3311 /* Did we encounter a breakpoint? */
3312 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3313 {
3314 dbg_breakpoint(sp->fname, sourcing_lnum);
3315 /* Find next breakpoint. */
3316 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3317 sp->dbg_tick = debug_tick;
3318 }
3319#endif
3320
3321 return line;
3322}
3323
3324 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003325get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326{
3327 garray_T ga;
3328 int len;
3329 int c;
3330 char_u *buf;
3331#ifdef USE_CRNL
3332 int has_cr; /* CR-LF found */
3333#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 int have_read = FALSE;
3335
3336 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003337 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338
3339 /*
3340 * Loop until there is a finished line (or end-of-file).
3341 */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003342 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 for (;;)
3344 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003345 /* make room to read at least 120 (more) characters */
3346 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347 break;
3348 buf = (char_u *)ga.ga_data;
3349
Bram Moolenaar00590742019-02-15 21:06:09 +01003350 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003351 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003352 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003353 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354#ifdef USE_CRNL
3355 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3356 * CTRL-Z by its own, or after a NL. */
3357 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3358 && sp->fileformat == EOL_DOS
3359 && buf[len - 1] == Ctrl_Z)
3360 {
3361 buf[len - 1] = NUL;
3362 break;
3363 }
3364#endif
3365
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367 ga.ga_len = len;
3368
3369 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003370 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 continue;
3372
3373 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3374 {
3375#ifdef USE_CRNL
3376 has_cr = (len >= 2 && buf[len - 2] == '\r');
3377 if (sp->fileformat == EOL_UNKNOWN)
3378 {
3379 if (has_cr)
3380 sp->fileformat = EOL_DOS;
3381 else
3382 sp->fileformat = EOL_UNIX;
3383 }
3384
3385 if (sp->fileformat == EOL_DOS)
3386 {
3387 if (has_cr) /* replace trailing CR */
3388 {
3389 buf[len - 2] = '\n';
3390 --len;
3391 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 }
3393 else /* lines like ":map xx yy^M" will have failed */
3394 {
3395 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003396 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003397 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003398 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003399 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400 sp->error = TRUE;
3401 sp->fileformat = EOL_UNIX;
3402 }
3403 }
3404#endif
3405 /* The '\n' is escaped if there is an odd number of ^V's just
3406 * before it, first set "c" just before the 'V's and then check
3407 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3408 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3409 ;
3410 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3411 {
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02003412 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003413 continue;
3414 }
3415
3416 buf[len - 1] = NUL; /* remove the NL */
3417 }
3418
3419 /*
3420 * Check for ^C here now and then, so recursive :so can be broken.
3421 */
3422 line_breakcheck();
3423 break;
3424 }
3425
3426 if (have_read)
3427 return (char_u *)ga.ga_data;
3428
3429 vim_free(ga.ga_data);
3430 return NULL;
3431}
3432
3433/*
3434 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003436 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003437ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003439 struct source_cookie *sp;
3440 char_u *name;
3441
3442 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3443 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003444 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445 return;
3446 }
3447
3448 if (*eap->arg != NUL)
3449 {
3450 name = enc_canonize(eap->arg);
3451 if (name == NULL) /* out of memory */
3452 return;
3453 }
3454 else
3455 name = eap->arg;
3456
3457 /* Setup for conversion from the specified encoding to 'encoding'. */
3458 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3459 convert_setup(&sp->conv, name, p_enc);
3460
3461 if (name != eap->arg)
3462 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463}
3464
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003465/*
3466 * ":scriptversion": Set Vim script version for a sourced script.
3467 */
3468 void
3469ex_scriptversion(exarg_T *eap UNUSED)
3470{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02003471#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003472 int nr;
3473
3474 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3475 {
3476 emsg(_("E984: :scriptversion used outside of a sourced file"));
3477 return;
3478 }
3479
3480 nr = getdigits(&eap->arg);
3481 if (nr == 0 || *eap->arg != NUL)
3482 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02003483 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003484 semsg(_("E999: scriptversion not supported: %d"), nr);
3485 else
3486 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02003487#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003488}
3489
Bram Moolenaar071d4272004-06-13 20:20:40 +00003490#if defined(FEAT_EVAL) || defined(PROTO)
3491/*
3492 * ":finish": Mark a sourced file as finished.
3493 */
3494 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003495ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003496{
3497 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3498 do_finish(eap, FALSE);
3499 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003500 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003501}
3502
3503/*
3504 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3505 * Also called for a pending finish at the ":endtry" or after returning from
3506 * an extra do_cmdline(). "reanimate" is used in the latter case.
3507 */
3508 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003509do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510{
3511 int idx;
3512
3513 if (reanimate)
3514 ((struct source_cookie *)getline_cookie(eap->getline,
3515 eap->cookie))->finished = FALSE;
3516
3517 /*
3518 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3519 * not in its finally clause (which then is to be executed next) is found.
3520 * In this case, make the ":finish" pending for execution at the ":endtry".
3521 * Otherwise, finish normally.
3522 */
3523 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3524 if (idx >= 0)
3525 {
3526 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3527 report_make_pending(CSTP_FINISH, NULL);
3528 }
3529 else
3530 ((struct source_cookie *)getline_cookie(eap->getline,
3531 eap->cookie))->finished = TRUE;
3532}
3533
3534
3535/*
3536 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3537 * message for missing ":endif".
3538 * Return FALSE when not sourcing a file.
3539 */
3540 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003541source_finished(
Bram Moolenaare96a2492019-06-25 04:12:16 +02003542 char_u *(*fgetline)(int, void *, int, int),
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003543 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003545 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003547 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548}
3549#endif
3550
Bram Moolenaar071d4272004-06-13 20:20:40 +00003551/*
3552 * ":checktime [buffer]"
3553 */
3554 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003555ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003556{
3557 buf_T *buf;
3558 int save_no_check_timestamps = no_check_timestamps;
3559
3560 no_check_timestamps = 0;
3561 if (eap->addr_count == 0) /* default is all buffers */
3562 check_timestamps(FALSE);
3563 else
3564 {
3565 buf = buflist_findnr((int)eap->line2);
3566 if (buf != NULL) /* cannot happen? */
3567 (void)buf_check_timestamp(buf, FALSE);
3568 }
3569 no_check_timestamps = save_no_check_timestamps;
3570}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571
Bram Moolenaar071d4272004-06-13 20:20:40 +00003572#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3573 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003574# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003575 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003576get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003578 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003579
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003580 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003581 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582
Bram Moolenaar4f974752019-02-17 17:44:42 +01003583# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 if (loc != NULL)
3585 {
3586 char_u *p;
3587
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003588 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
3589 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 p = vim_strchr(loc, '=');
3591 if (p != NULL)
3592 {
3593 loc = ++p;
3594 while (*p != NUL) /* remove trailing newline */
3595 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003596 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 {
3598 *p = NUL;
3599 break;
3600 }
3601 ++p;
3602 }
3603 }
3604 }
3605# endif
3606
3607 return loc;
3608}
3609#endif
3610
3611
Bram Moolenaar4f974752019-02-17 17:44:42 +01003612#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613/*
3614 * On MS-Windows locale names are strings like "German_Germany.1252", but
3615 * gettext expects "de". Try to translate one into another here for a few
3616 * supported languages.
3617 */
3618 static char_u *
3619gettext_lang(char_u *name)
3620{
3621 int i;
3622 static char *(mtable[]) = {
3623 "afrikaans", "af",
3624 "czech", "cs",
3625 "dutch", "nl",
3626 "german", "de",
3627 "english_united kingdom", "en_GB",
3628 "spanish", "es",
3629 "french", "fr",
3630 "italian", "it",
3631 "japanese", "ja",
3632 "korean", "ko",
3633 "norwegian", "no",
3634 "polish", "pl",
3635 "russian", "ru",
3636 "slovak", "sk",
3637 "swedish", "sv",
3638 "ukrainian", "uk",
3639 "chinese_china", "zh_CN",
3640 "chinese_taiwan", "zh_TW",
3641 NULL};
3642
3643 for (i = 0; mtable[i] != NULL; i += 2)
3644 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003645 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 return name;
3647}
3648#endif
3649
3650#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3651/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01003652 * Return TRUE when "lang" starts with a valid language name.
3653 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
3654 */
3655 static int
3656is_valid_mess_lang(char_u *lang)
3657{
3658 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
3659}
3660
3661/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662 * Obtain the current messages language. Used to set the default for
3663 * 'helplang'. May return NULL or an empty string.
3664 */
3665 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003666get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667{
3668 char_u *p;
3669
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003670# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003672 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673# else
3674 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003675 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3676 * and LC_MONETARY may be set differently for a Japanese working in the
3677 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003678 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679# endif
3680# else
3681 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003682 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683 {
3684 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003685 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686 p = mch_getenv((char_u *)"LANG");
3687 }
3688# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003689# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 p = gettext_lang(p);
3691# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01003692 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693}
3694#endif
3695
Bram Moolenaardef9e822004-12-31 20:58:58 +00003696/* Complicated #if; matches with where get_mess_env() is used below. */
3697#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3698 && defined(LC_MESSAGES))) \
3699 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00003700 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701/*
3702 * Get the language used for messages from the environment.
3703 */
3704 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003705get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706{
3707 char_u *p;
3708
3709 p = mch_getenv((char_u *)"LC_ALL");
3710 if (p == NULL || *p == NUL)
3711 {
3712 p = mch_getenv((char_u *)"LC_MESSAGES");
3713 if (p == NULL || *p == NUL)
3714 {
3715 p = mch_getenv((char_u *)"LANG");
3716 if (p != NULL && VIM_ISDIGIT(*p))
3717 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003718# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003720 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721# endif
3722 }
3723 }
3724 return p;
3725}
3726#endif
3727
3728#if defined(FEAT_EVAL) || defined(PROTO)
3729
3730/*
3731 * Set the "v:lang" variable according to the current locale setting.
3732 * Also do "v:lc_time"and "v:ctype".
3733 */
3734 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003735set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736{
3737 char_u *loc;
3738
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003739# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003740 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741# else
3742 /* setlocale() not supported: use the default value */
3743 loc = (char_u *)"C";
3744# endif
3745 set_vim_var_string(VV_CTYPE, loc, -1);
3746
3747 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3748 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003749# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003750 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751# else
3752 loc = get_mess_env();
3753# endif
3754 set_vim_var_string(VV_LANG, loc, -1);
3755
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003756# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003757 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758# endif
3759 set_vim_var_string(VV_LC_TIME, loc, -1);
3760}
3761#endif
3762
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01003763#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764/*
3765 * ":language": Set the language (locale).
3766 */
3767 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003768ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769{
3770 char *loc;
3771 char_u *p;
3772 char_u *name;
3773 int what = LC_ALL;
3774 char *whatstr = "";
3775#ifdef LC_MESSAGES
3776# define VIM_LC_MESSAGES LC_MESSAGES
3777#else
3778# define VIM_LC_MESSAGES 6789
3779#endif
3780
3781 name = eap->arg;
3782
3783 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3784 * Allow abbreviation, but require at least 3 characters to avoid
3785 * confusion with a two letter language name "me" or "ct". */
3786 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003787 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 {
3789 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3790 {
3791 what = VIM_LC_MESSAGES;
3792 name = skipwhite(p);
3793 whatstr = "messages ";
3794 }
3795 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3796 {
3797 what = LC_CTYPE;
3798 name = skipwhite(p);
3799 whatstr = "ctype ";
3800 }
3801 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3802 {
3803 what = LC_TIME;
3804 name = skipwhite(p);
3805 whatstr = "time ";
3806 }
3807 }
3808
3809 if (*name == NUL)
3810 {
3811#ifndef LC_MESSAGES
3812 if (what == VIM_LC_MESSAGES)
3813 p = get_mess_env();
3814 else
3815#endif
3816 p = (char_u *)setlocale(what, NULL);
3817 if (p == NULL || *p == NUL)
3818 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003819 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 }
3821 else
3822 {
3823#ifndef LC_MESSAGES
3824 if (what == VIM_LC_MESSAGES)
3825 loc = "";
3826 else
3827#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003828 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003830#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
3831 /* Make sure strtod() uses a decimal point, not a comma. */
3832 setlocale(LC_NUMERIC, "C");
3833#endif
3834 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003836 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 else
3838 {
3839#ifdef HAVE_NL_MSG_CAT_CNTR
3840 /* Need to do this for GNU gettext, otherwise cached translations
3841 * will be used again. */
3842 extern int _nl_msg_cat_cntr;
3843
3844 ++_nl_msg_cat_cntr;
3845#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00003846 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
3848
3849 if (what != LC_TIME)
3850 {
3851 /* Tell gettext() what to translate to. It apparently doesn't
3852 * use the currently effective locale. Also do this when
3853 * FEAT_GETTEXT isn't defined, so that shell commands use this
3854 * value. */
3855 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003856 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003857 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02003858
3859 /* Clear $LANGUAGE because GNU gettext uses it. */
3860 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01003861# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003862 /* Apparently MS-Windows printf() may cause a crash when
3863 * we give it 8-bit text while it's expecting text in the
3864 * current locale. This call avoids that. */
3865 setlocale(LC_CTYPE, "C");
3866# endif
3867 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 if (what != LC_CTYPE)
3869 {
3870 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003871#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 mname = gettext_lang(name);
3873#else
3874 mname = name;
3875#endif
3876 vim_setenv((char_u *)"LC_MESSAGES", mname);
3877#ifdef FEAT_MULTI_LANG
3878 set_helplang_default(mname);
3879#endif
3880 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 }
3882
3883# ifdef FEAT_EVAL
3884 /* Set v:lang, v:lc_time and v:ctype to the final result. */
3885 set_lang_var();
3886# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02003887# ifdef FEAT_TITLE
3888 maketitle();
3889# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890 }
3891 }
3892}
3893
3894# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003895
3896static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003897
Bram Moolenaar4f974752019-02-17 17:44:42 +01003898# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003899static int did_init_locales = FALSE;
3900
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003901/* Return an array of strings for all available locales + NULL for the
3902 * last element. Return NULL in case of error. */
3903 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003904find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003905{
3906 garray_T locales_ga;
3907 char_u *loc;
3908
3909 /* Find all available locales by running command "locale -a". If this
3910 * doesn't work we won't have completion. */
3911 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02003912 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003913 if (locale_a == NULL)
3914 return NULL;
3915 ga_init2(&locales_ga, sizeof(char_u *), 20);
3916
3917 /* Transform locale_a string where each locale is separated by "\n"
3918 * into an array of locale strings. */
3919 loc = (char_u *)strtok((char *)locale_a, "\n");
3920
3921 while (loc != NULL)
3922 {
3923 if (ga_grow(&locales_ga, 1) == FAIL)
3924 break;
3925 loc = vim_strsave(loc);
3926 if (loc == NULL)
3927 break;
3928
3929 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
3930 loc = (char_u *)strtok(NULL, "\n");
3931 }
3932 vim_free(locale_a);
3933 if (ga_grow(&locales_ga, 1) == FAIL)
3934 {
3935 ga_clear(&locales_ga);
3936 return NULL;
3937 }
3938 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
3939 return (char_u **)locales_ga.ga_data;
3940}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003941# endif
3942
3943/*
3944 * Lazy initialization of all available locales.
3945 */
3946 static void
3947init_locales(void)
3948{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003949# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003950 if (!did_init_locales)
3951 {
3952 did_init_locales = TRUE;
3953 locales = find_locales();
3954 }
3955# endif
3956}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003957
3958# if defined(EXITFREE) || defined(PROTO)
3959 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003960free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003961{
3962 int i;
3963 if (locales != NULL)
3964 {
3965 for (i = 0; locales[i] != NULL; i++)
3966 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01003967 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003968 }
3969}
3970# endif
3971
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972/*
3973 * Function given to ExpandGeneric() to obtain the possible arguments of the
3974 * ":language" command.
3975 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003977get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978{
3979 if (idx == 0)
3980 return (char_u *)"messages";
3981 if (idx == 1)
3982 return (char_u *)"ctype";
3983 if (idx == 2)
3984 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003985
3986 init_locales();
3987 if (locales == NULL)
3988 return NULL;
3989 return locales[idx - 3];
3990}
3991
3992/*
3993 * Function given to ExpandGeneric() to obtain the available locales.
3994 */
3995 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003996get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003997{
3998 init_locales();
3999 if (locales == NULL)
4000 return NULL;
4001 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002}
4003# endif
4004
4005#endif