blob: c0bf0e97168fa5bf068095c4a2631a2aefcb4569 [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/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200826 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 */
828 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100829ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830{
831 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000832 win_T *wp;
833 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +0100834 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100836#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000839 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200840#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +0200841 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200842 int qf_idx;
843#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844
Bram Moolenaar0106e3d2016-02-23 18:55:43 +0100845#ifndef FEAT_QUICKFIX
846 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
847 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
848 {
849 ex_ni(eap);
850 return;
851 }
852#endif
853
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100854#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000855 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200856 {
Bram Moolenaardcaf10e2005-01-21 11:55:25 +0000857 /* Don't do syntax HL autocommands. Skipping the syntax file is a
858 * great speed improvement. */
859 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200860
861 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
862 buf->b_flags &= ~BF_SYN_SET;
863 buf = curbuf;
864 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200866#ifdef FEAT_CLIPBOARD
867 start_global_changes();
868#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869
870 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000871 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +0200872 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100873 || !check_changed(curbuf, CCGD_AW
874 | (eap->forceit ? CCGD_FORCEIT : 0)
875 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100878 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000879 wp = firstwin;
880 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100881 switch (eap->cmdidx)
882 {
Bram Moolenaara162bc52015-01-07 16:54:21 +0100883 case CMD_windo:
884 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
885 i++;
886 break;
887 case CMD_tabdo:
888 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
889 i++;
890 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100891 case CMD_argdo:
892 i = eap->line1 - 1;
893 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100894 default:
895 break;
896 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 /* set pcmark now */
898 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200899 {
Bram Moolenaare25bb902015-02-27 20:33:37 +0100900 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200901 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +0100902 || !buf->b_p_bl); buf = buf->b_next)
903 if (buf->b_fnum > eap->line2)
904 {
905 buf = NULL;
906 break;
907 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200908 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +0100909 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200910 }
911#ifdef FEAT_QUICKFIX
912 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
913 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
914 {
Bram Moolenaar25190db2019-05-04 15:05:28 +0200915 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200916 if (qf_size <= 0 || eap->line1 > qf_size)
917 buf = NULL;
918 else
919 {
920 ex_cc(eap);
921
922 buf = curbuf;
923 i = eap->line1 - 1;
924 if (eap->addr_count <= 0)
925 /* default is all the quickfix/location list entries */
926 eap->line2 = qf_size;
927 }
928 }
929#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930 else
931 setpcmark();
932 listcmd_busy = TRUE; /* avoids setting pcmark below */
933
Bram Moolenaare25bb902015-02-27 20:33:37 +0100934 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 {
936 if (eap->cmdidx == CMD_argdo)
937 {
938 /* go to argument "i" */
939 if (i == ARGCOUNT)
940 break;
941 /* Don't call do_argfile() when already there, it will try
942 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000943 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000944 {
945 /* Clear 'shm' to avoid that the file message overwrites
946 * any output from the command. */
947 p_shm_save = vim_strsave(p_shm);
948 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000950 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
951 vim_free(p_shm_save);
952 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953 if (curwin->w_arg_idx != i)
954 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956 else if (eap->cmdidx == CMD_windo)
957 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000958 /* go to window "wp" */
959 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000961 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +0000962 if (curwin != wp)
963 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000964 wp = curwin->w_next;
965 }
966 else if (eap->cmdidx == CMD_tabdo)
967 {
968 /* go to window "tp" */
969 if (!valid_tabpage(tp))
970 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200971 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000972 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000973 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974 else if (eap->cmdidx == CMD_bufdo)
975 {
976 /* Remember the number of the next listed buffer, in case
977 * ":bwipe" is used or autocommands do something strange. */
978 next_fnum = -1;
979 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
980 if (buf->b_p_bl)
981 {
982 next_fnum = buf->b_fnum;
983 break;
984 }
985 }
986
Bram Moolenaara162bc52015-01-07 16:54:21 +0100987 ++i;
988
Bram Moolenaar071d4272004-06-13 20:20:40 +0000989 /* execute the command */
990 do_cmdline(eap->arg, eap->getline, eap->cookie,
991 DOCMD_VERBOSE + DOCMD_NOWAIT);
992
993 if (eap->cmdidx == CMD_bufdo)
994 {
995 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +0100996 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000997 break;
998 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +0200999 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000 if (buf->b_fnum == next_fnum)
1001 break;
1002 if (buf == NULL)
1003 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001004
1005 /* Go to the next buffer. Clear 'shm' to avoid that the file
1006 * message overwrites any output from the command. */
1007 p_shm_save = vim_strsave(p_shm);
1008 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001010 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1011 vim_free(p_shm_save);
1012
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001013 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014 if (curbuf->b_fnum != next_fnum)
1015 break;
1016 }
1017
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001018#ifdef FEAT_QUICKFIX
1019 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1020 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1021 {
1022 if (i >= qf_size || i >= eap->line2)
1023 break;
1024
1025 qf_idx = qf_get_cur_idx(eap);
1026
1027 ex_cnext(eap);
1028
1029 /* If jumping to the next quickfix entry fails, quit here */
1030 if (qf_get_cur_idx(eap) == qf_idx)
1031 break;
1032 }
1033#endif
1034
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035 if (eap->cmdidx == CMD_windo)
1036 {
1037 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01001038
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 /* required when 'scrollbind' has been set */
1040 if (curwin->w_p_scb)
1041 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001042 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01001043
Bram Moolenaara162bc52015-01-07 16:54:21 +01001044 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
1045 if (i+1 > eap->line2)
1046 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001047 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
1048 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049 }
1050 listcmd_busy = FALSE;
1051 }
1052
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001053#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001054 if (save_ei != NULL)
1055 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001056 buf_T *bnext;
1057 aco_save_T aco;
1058
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001059 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001060
1061 for (buf = firstbuf; buf != NULL; buf = bnext)
1062 {
1063 bnext = buf->b_next;
1064 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
1065 {
1066 buf->b_flags &= ~BF_SYN_SET;
1067
1068 // buffer was opened while Syntax autocommands were disabled,
1069 // need to trigger them now.
1070 if (buf == curbuf)
1071 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001072 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001073 else
1074 {
1075 aucmd_prepbuf(&aco, buf);
1076 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
1077 buf->b_fname, TRUE, buf);
1078 aucmd_restbuf(&aco);
1079 }
1080
1081 // start over, in case autocommands messed things up.
1082 bnext = firstbuf;
1083 }
1084 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001085 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001087#ifdef FEAT_CLIPBOARD
1088 end_global_changes();
1089#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090}
1091
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092#ifdef FEAT_EVAL
1093/*
1094 * ":compiler[!] {name}"
1095 */
1096 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001097ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098{
1099 char_u *buf;
1100 char_u *old_cur_comp = NULL;
1101 char_u *p;
1102
1103 if (*eap->arg == NUL)
1104 {
1105 /* List all compiler scripts. */
1106 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1107 /* ) keep the indenter happy... */
1108 }
1109 else
1110 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02001111 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 if (buf != NULL)
1113 {
1114 if (eap->forceit)
1115 {
1116 /* ":compiler! {name}" sets global options */
1117 do_cmdline_cmd((char_u *)
1118 "command -nargs=* CompilerSet set <args>");
1119 }
1120 else
1121 {
1122 /* ":compiler! {name}" sets local options.
1123 * To remain backwards compatible "current_compiler" is always
1124 * used. A user's compiler plugin may set it, the distributed
1125 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001126 * "b:current_compiler" and restore "current_compiler".
1127 * Explicitly prepend "g:" to make it work in a function. */
1128 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 if (old_cur_comp != NULL)
1130 old_cur_comp = vim_strsave(old_cur_comp);
1131 do_cmdline_cmd((char_u *)
1132 "command -nargs=* CompilerSet setlocal <args>");
1133 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001134 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00001135 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001136
1137 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001138 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001139 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001140 vim_free(buf);
1141
1142 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1143
1144 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001145 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146 if (p != NULL)
1147 set_internal_string_var((char_u *)"b:current_compiler", p);
1148
1149 /* Restore "current_compiler" for ":compiler {name}". */
1150 if (!eap->forceit)
1151 {
1152 if (old_cur_comp != NULL)
1153 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001154 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 old_cur_comp);
1156 vim_free(old_cur_comp);
1157 }
1158 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001159 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 }
1161 }
1162 }
1163}
1164#endif
1165
1166/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001167 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168 */
1169 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001170ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001172 char_u *arg = eap->arg;
1173 char_u *p = skiptowhite(arg);
1174 int len = (int)(p - arg);
1175 int flags = eap->forceit ? DIP_ALL : 0;
1176
1177 if (STRNCMP(arg, "START", len) == 0)
1178 {
1179 flags += DIP_START + DIP_NORTP;
1180 arg = skipwhite(arg + len);
1181 }
1182 else if (STRNCMP(arg, "OPT", len) == 0)
1183 {
1184 flags += DIP_OPT + DIP_NORTP;
1185 arg = skipwhite(arg + len);
1186 }
1187 else if (STRNCMP(arg, "PACK", len) == 0)
1188 {
1189 flags += DIP_START + DIP_OPT + DIP_NORTP;
1190 arg = skipwhite(arg + len);
1191 }
1192 else if (STRNCMP(arg, "ALL", len) == 0)
1193 {
1194 flags += DIP_START + DIP_OPT;
1195 arg = skipwhite(arg + len);
1196 }
1197
1198 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001199}
1200
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001202source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001204 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205}
1206
1207/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001208 * Find the file "name" in all directories in "path" and invoke
1209 * "callback(fname, cookie)".
1210 * "name" can contain wildcards.
1211 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
1212 * When "flags" has DIP_DIR: find directories instead of files.
1213 * When "flags" has DIP_ERR: give an error message if there is no match.
1214 *
1215 * return FAIL when no file could be sourced, OK otherwise.
1216 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01001217 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001218do_in_path(
1219 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001220 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01001221 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001222 void (*callback)(char_u *fname, void *ck),
1223 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224{
1225 char_u *rtp;
1226 char_u *np;
1227 char_u *buf;
1228 char_u *rtp_copy;
1229 char_u *tail;
1230 int num_files;
1231 char_u **files;
1232 int i;
1233 int did_one = FALSE;
1234#ifdef AMIGA
1235 struct Process *proc = (struct Process *)FindTask(0L);
1236 APTR save_winptr = proc->pr_WindowPtr;
1237
1238 /* Avoid a requester here for a volume that doesn't exist. */
1239 proc->pr_WindowPtr = (APTR)-1L;
1240#endif
1241
1242 /* Make a copy of 'runtimepath'. Invoking the callback may change the
1243 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001244 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245 buf = alloc(MAXPATHL);
1246 if (buf != NULL && rtp_copy != NULL)
1247 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001248 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001249 {
1250 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001251 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001252 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001253 verbose_leave();
1254 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001255
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 /* Loop over all entries in 'runtimepath'. */
1257 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01001258 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02001260 size_t buflen;
1261
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 /* Copy the path from 'runtimepath' to buf[]. */
1263 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02001264 buflen = STRLEN(buf);
1265
1266 /* Skip after or non-after directories. */
1267 if (flags & (DIP_NOAFTER | DIP_AFTER))
1268 {
1269 int is_after = buflen >= 5
1270 && STRCMP(buf + buflen - 5, "after") == 0;
1271
1272 if ((is_after && (flags & DIP_NOAFTER))
1273 || (!is_after && (flags & DIP_AFTER)))
1274 continue;
1275 }
1276
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02001277 if (name == NULL)
1278 {
1279 (*callback)(buf, (void *) &cookie);
1280 if (!did_one)
1281 did_one = (cookie == NULL);
1282 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02001283 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284 {
1285 add_pathsep(buf);
1286 tail = buf + STRLEN(buf);
1287
1288 /* Loop over all patterns in "name" */
1289 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01001290 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291 {
1292 /* Append the pattern from "name" to buf[]. */
1293 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
1294 "\t ");
1295
1296 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001297 {
1298 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001299 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001300 verbose_leave();
1301 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302
1303 /* Expand wildcards, invoke the callback for each match. */
1304 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01001305 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306 {
1307 for (i = 0; i < num_files; ++i)
1308 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001309 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01001311 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312 break;
1313 }
1314 FreeWild(num_files, files);
1315 }
1316 }
1317 }
1318 }
1319 }
1320 vim_free(buf);
1321 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001322 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001323 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001324 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
1325
1326 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001327 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001328 else if (p_verbose > 0)
1329 {
1330 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001331 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01001332 verbose_leave();
1333 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00001334 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001335
1336#ifdef AMIGA
1337 proc->pr_WindowPtr = save_winptr;
1338#endif
1339
1340 return did_one ? OK : FAIL;
1341}
1342
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001343/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001344 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001345 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001346 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
1347 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001348 * Returns OK when at least one match found, FAIL otherwise.
1349 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001350 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001351 * passed by reference in this case, setting it to NULL indicates that callback
1352 * has done its job.
1353 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001354 static int
1355do_in_path_and_pp(
1356 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001357 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001358 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001359 void (*callback)(char_u *fname, void *ck),
1360 void *cookie)
1361{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001362 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001363 char_u *s;
1364 int len;
1365 char *start_dir = "pack/*/start/*/%s";
1366 char *opt_dir = "pack/*/opt/*/%s";
1367
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001368 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001369 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001370
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001371 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001372 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01001373 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001374 s = alloc(len);
1375 if (s == NULL)
1376 return FAIL;
1377 vim_snprintf((char *)s, len, start_dir, name);
1378 done = do_in_path(p_pp, s, flags, callback, cookie);
1379 vim_free(s);
1380 }
1381
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01001382 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001383 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01001384 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001385 s = alloc(len);
1386 if (s == NULL)
1387 return FAIL;
1388 vim_snprintf((char *)s, len, opt_dir, name);
1389 done = do_in_path(p_pp, s, flags, callback, cookie);
1390 vim_free(s);
1391 }
1392
1393 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001394}
1395
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01001396/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001397 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
1398 */
1399 int
1400do_in_runtimepath(
1401 char_u *name,
1402 int flags,
1403 void (*callback)(char_u *fname, void *ck),
1404 void *cookie)
1405{
1406 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
1407}
1408
1409/*
1410 * Source the file "name" from all directories in 'runtimepath'.
1411 * "name" can contain wildcards.
1412 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
1413 *
1414 * return FAIL when no file could be sourced, OK otherwise.
1415 */
1416 int
1417source_runtime(char_u *name, int flags)
1418{
1419 return source_in_path(p_rtp, name, flags);
1420}
1421
1422/*
1423 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
1424 */
1425 int
1426source_in_path(char_u *path, char_u *name, int flags)
1427{
1428 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
1429}
1430
1431
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001432#if defined(FEAT_EVAL) || defined(PROTO)
1433
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02001434/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01001435 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01001436 */
1437 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01001438source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01001439{
Bram Moolenaarf3654822016-03-04 22:12:23 +01001440 int num_files;
1441 char_u **files;
1442 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01001443
Bram Moolenaarf3654822016-03-04 22:12:23 +01001444 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01001445 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01001446 for (i = 0; i < num_files; ++i)
1447 (void)do_source(files[i], FALSE, DOSO_NONE);
1448 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01001449 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01001450}
1451
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001452/*
1453 * Add the package directory to 'runtimepath'.
1454 */
1455 static int
1456add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001457{
Bram Moolenaarf3654822016-03-04 22:12:23 +01001458 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02001459 char_u *entry;
1460 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01001461 int c;
1462 char_u *new_rtp;
1463 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02001464 size_t oldlen;
1465 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02001466 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001467 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02001468 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02001469 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001470 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02001471 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01001472 char_u *buf = NULL;
1473 char_u *rtp_ffname;
1474 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001475 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001476
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001477 p4 = p3 = p2 = p1 = get_past_head(fname);
1478 for (p = p1; *p; MB_PTR_ADV(p))
1479 if (vim_ispathsep_nocolon(*p))
1480 {
1481 p4 = p3; p3 = p2; p2 = p1; p1 = p;
1482 }
1483
1484 /* now we have:
1485 * rtp/pack/name/start/name
1486 * p4 p3 p2 p1
1487 *
1488 * find the part up to "pack" in 'runtimepath' */
1489 c = *++p4; /* append pathsep in order to expand symlink */
1490 *p4 = NUL;
1491 ffname = fix_fname(fname);
1492 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01001493 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001494 return FAIL;
1495
Bram Moolenaar99396d42018-09-08 18:21:16 +02001496 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
1497 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001498 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001499 buf = alloc(MAXPATHL);
1500 if (buf == NULL)
1501 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02001502 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001503 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02001504 char_u *cur_entry = entry;
1505
1506 copy_option_part(&entry, buf, MAXPATHL, ",");
1507 if (insp == NULL)
1508 {
1509 add_pathsep(buf);
1510 rtp_ffname = fix_fname(buf);
1511 if (rtp_ffname == NULL)
1512 goto theend;
1513 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
1514 vim_free(rtp_ffname);
1515 if (match)
1516 // Insert "ffname" after this entry (and comma).
1517 insp = entry;
1518 }
1519
1520 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
1521 && p > buf
1522 && vim_ispathsep(p[-1])
1523 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
1524 {
1525 if (insp == NULL)
1526 // Did not find "ffname" before the first "after" directory,
1527 // insert it before this entry.
1528 insp = cur_entry;
1529 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001530 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02001531 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001532 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001533
Bram Moolenaar99396d42018-09-08 18:21:16 +02001534 if (insp == NULL)
1535 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001536 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001537
Bram Moolenaar99396d42018-09-08 18:21:16 +02001538 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001539 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
1540 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02001541 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001542
1543 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02001544 addlen = STRLEN(fname) + 1; // add one for comma
Bram Moolenaar51e14382019-05-25 20:21:28 +02001545 new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001546 if (new_rtp == NULL)
1547 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02001548
1549 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
1550 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001551 keep = (int)(insp - p_rtp);
1552 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02001553 new_rtp_len = keep;
1554 if (*insp == NUL)
1555 new_rtp[new_rtp_len++] = ','; // add comma before
1556 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
1557 new_rtp_len += addlen - 1;
1558 if (*insp != NUL)
1559 new_rtp[new_rtp_len++] = ','; // add comma after
1560
1561 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01001562 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02001563 int keep_after = (int)(after_insp - p_rtp);
1564
1565 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
1566 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
1567 keep_after - keep);
1568 new_rtp_len += keep_after - keep;
1569 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
1570 new_rtp_len += afterlen - 1;
1571 new_rtp[new_rtp_len++] = ',';
1572 keep = keep_after;
1573 }
1574
1575 if (p_rtp[keep] != NUL)
1576 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
1577 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
1578 else
1579 new_rtp[new_rtp_len] = NUL;
1580
1581 if (afterlen > 0 && after_insp == NULL)
1582 {
1583 // Append afterdir when "after" was not found:
1584 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001585 STRCAT(new_rtp, ",");
1586 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01001587 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02001588
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001589 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
1590 vim_free(new_rtp);
1591 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01001592
1593theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01001594 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01001595 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001596 vim_free(afterdir);
1597 return retval;
1598}
1599
1600/*
1601 * Load scripts in "plugin" and "ftdetect" directories of the package.
1602 */
1603 static int
1604load_pack_plugin(char_u *fname)
1605{
1606 static char *plugpat = "%s/plugin/**/*.vim";
1607 static char *ftpat = "%s/ftdetect/*.vim";
1608 int len;
1609 char_u *ffname = fix_fname(fname);
1610 char_u *pat = NULL;
1611 int retval = FAIL;
1612
1613 if (ffname == NULL)
1614 return FAIL;
1615 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
1616 pat = alloc(len);
1617 if (pat == NULL)
1618 goto theend;
1619 vim_snprintf((char *)pat, len, plugpat, ffname);
1620 source_all_matches(pat);
1621
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001622 {
1623 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
1624
1625 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
1626 * found when it loads. */
1627 if (cmd != NULL && eval_to_number(cmd) > 0)
1628 {
1629 do_cmdline_cmd((char_u *)"augroup filetypedetect");
1630 vim_snprintf((char *)pat, len, ftpat, ffname);
1631 source_all_matches(pat);
1632 do_cmdline_cmd((char_u *)"augroup END");
1633 }
1634 vim_free(cmd);
1635 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001636 vim_free(pat);
1637 retval = OK;
1638
1639theend:
1640 vim_free(ffname);
1641 return retval;
1642}
1643
1644/* used for "cookie" of add_pack_plugin() */
1645static int APP_ADD_DIR;
1646static int APP_LOAD;
1647static int APP_BOTH;
1648
1649 static void
1650add_pack_plugin(char_u *fname, void *cookie)
1651{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02001652 if (cookie != &APP_LOAD)
1653 {
1654 char_u *buf = alloc(MAXPATHL);
1655 char_u *p;
1656 int found = FALSE;
1657
1658 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001659 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02001660 p = p_rtp;
1661 while (*p != NUL)
1662 {
1663 copy_option_part(&p, buf, MAXPATHL, ",");
1664 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
1665 {
1666 found = TRUE;
1667 break;
1668 }
1669 }
1670 vim_free(buf);
1671 if (!found)
1672 /* directory is not yet in 'runtimepath', add it */
1673 if (add_pack_dir_to_rtp(fname) == FAIL)
1674 return;
1675 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01001676
1677 if (cookie != &APP_ADD_DIR)
1678 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001679}
1680
Bram Moolenaarce876aa2017-06-04 17:47:42 +02001681/*
1682 * Add all packages in the "start" directory to 'runtimepath'.
1683 */
1684 void
1685add_pack_start_dirs(void)
1686{
1687 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
1688 add_pack_plugin, &APP_ADD_DIR);
1689}
1690
1691/*
1692 * Load plugins from all packages in the "start" directory.
1693 */
1694 void
1695load_start_packages(void)
1696{
1697 did_source_packages = TRUE;
1698 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
1699 add_pack_plugin, &APP_LOAD);
1700}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01001701
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001702/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01001703 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01001704 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001705 */
1706 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01001707ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001708{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02001709 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01001710 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02001711 /* First do a round to add all directories to 'runtimepath', then load
1712 * the plugins. This allows for plugins to use an autoload directory
1713 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02001714 add_pack_start_dirs();
1715 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01001716 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01001717}
1718
1719/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01001720 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01001721 */
1722 void
1723ex_packadd(exarg_T *eap)
1724{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01001725 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01001726 int len;
1727 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01001728 int round;
1729 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01001730
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01001731 /* Round 1: use "start", round 2: use "opt". */
1732 for (round = 1; round <= 2; ++round)
1733 {
1734 /* Only look under "start" when loading packages wasn't done yet. */
1735 if (round == 1 && did_source_packages)
1736 continue;
1737
1738 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001739 pat = alloc(len);
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01001740 if (pat == NULL)
1741 return;
1742 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
1743 /* The first round don't give a "not found" error, in the second round
1744 * only when nothing was found in the first round. */
1745 res = do_in_path(p_pp, (char_u *)pat,
1746 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
1747 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
1748 vim_free(pat);
1749 }
Bram Moolenaar91715872016-03-03 17:13:03 +01001750}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001751#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01001752
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001753#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754/*
1755 * ":options"
1756 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001758ex_options(
1759 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760{
Bram Moolenaare0b59492019-05-21 20:54:45 +02001761 vim_setenv((char_u *)"OPTWIN_CMD",
1762 (char_u *)(cmdmod.tab ? "tab"
1763 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
1765}
1766#endif
1767
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001768#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
1769
1770# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
1771/*
1772 * Detect Python 3 or 2, and initialize 'pyxversion'.
1773 */
1774 void
1775init_pyxversion(void)
1776{
1777 if (p_pyx == 0)
1778 {
1779 if (python3_enabled(FALSE))
1780 p_pyx = 3;
1781 else if (python_enabled(FALSE))
1782 p_pyx = 2;
1783 }
1784}
1785# endif
1786
1787/*
1788 * Does a file contain one of the following strings at the beginning of any
1789 * line?
1790 * "#!(any string)python2" => returns 2
1791 * "#!(any string)python3" => returns 3
1792 * "# requires python 2.x" => returns 2
1793 * "# requires python 3.x" => returns 3
1794 * otherwise return 0.
1795 */
1796 static int
1797requires_py_version(char_u *filename)
1798{
1799 FILE *file;
1800 int requires_py_version = 0;
1801 int i, lines;
1802
1803 lines = (int)p_mls;
1804 if (lines < 0)
1805 lines = 5;
1806
1807 file = mch_fopen((char *)filename, "r");
1808 if (file != NULL)
1809 {
1810 for (i = 0; i < lines; i++)
1811 {
1812 if (vim_fgets(IObuff, IOSIZE, file))
1813 break;
1814 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
1815 {
1816 /* Check shebang. */
1817 if (strstr((char *)IObuff + 2, "python2") != NULL)
1818 {
1819 requires_py_version = 2;
1820 break;
1821 }
1822 if (strstr((char *)IObuff + 2, "python3") != NULL)
1823 {
1824 requires_py_version = 3;
1825 break;
1826 }
1827 }
1828 IObuff[21] = '\0';
1829 if (STRCMP("# requires python 2.x", IObuff) == 0)
1830 {
1831 requires_py_version = 2;
1832 break;
1833 }
1834 if (STRCMP("# requires python 3.x", IObuff) == 0)
1835 {
1836 requires_py_version = 3;
1837 break;
1838 }
1839 }
1840 fclose(file);
1841 }
1842 return requires_py_version;
1843}
1844
1845
1846/*
1847 * Source a python file using the requested python version.
1848 */
1849 static void
1850source_pyx_file(exarg_T *eap, char_u *fname)
1851{
1852 exarg_T ex;
1853 int v = requires_py_version(fname);
1854
1855# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1856 init_pyxversion();
1857# endif
1858 if (v == 0)
1859 {
1860# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1861 /* user didn't choose a preference, 'pyx' is used */
1862 v = p_pyx;
1863# elif defined(FEAT_PYTHON)
1864 v = 2;
1865# elif defined(FEAT_PYTHON3)
1866 v = 3;
1867# endif
1868 }
1869
1870 /*
1871 * now source, if required python version is not supported show
1872 * unobtrusive message.
1873 */
1874 if (eap == NULL)
1875 vim_memset(&ex, 0, sizeof(ex));
1876 else
1877 ex = *eap;
1878 ex.arg = fname;
1879 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
1880
1881 if (v == 2)
1882 {
1883# ifdef FEAT_PYTHON
1884 ex_pyfile(&ex);
1885# else
1886 vim_snprintf((char *)IObuff, IOSIZE,
1887 _("W20: Required python version 2.x not supported, ignoring file: %s"),
1888 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01001889 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001890# endif
1891 return;
1892 }
1893 else
1894 {
1895# ifdef FEAT_PYTHON3
1896 ex_py3file(&ex);
1897# else
1898 vim_snprintf((char *)IObuff, IOSIZE,
1899 _("W21: Required python version 3.x not supported, ignoring file: %s"),
1900 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01001901 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001902# endif
1903 return;
1904 }
1905}
1906
1907/*
1908 * ":pyxfile {fname}"
1909 */
1910 void
1911ex_pyxfile(exarg_T *eap)
1912{
1913 source_pyx_file(eap, eap->arg);
1914}
1915
1916/*
1917 * ":pyx"
1918 */
1919 void
1920ex_pyx(exarg_T *eap)
1921{
1922# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1923 init_pyxversion();
1924 if (p_pyx == 2)
1925 ex_python(eap);
1926 else
1927 ex_py3(eap);
1928# elif defined(FEAT_PYTHON)
1929 ex_python(eap);
1930# elif defined(FEAT_PYTHON3)
1931 ex_py3(eap);
1932# endif
1933}
1934
1935/*
1936 * ":pyxdo"
1937 */
1938 void
1939ex_pyxdo(exarg_T *eap)
1940{
1941# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1942 init_pyxversion();
1943 if (p_pyx == 2)
1944 ex_pydo(eap);
1945 else
1946 ex_py3do(eap);
1947# elif defined(FEAT_PYTHON)
1948 ex_pydo(eap);
1949# elif defined(FEAT_PYTHON3)
1950 ex_py3do(eap);
1951# endif
1952}
1953
1954#endif
1955
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956/*
1957 * ":source {fname}"
1958 */
1959 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001960ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961{
1962#ifdef FEAT_BROWSE
1963 if (cmdmod.browse)
1964 {
1965 char_u *fname = NULL;
1966
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001967 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02001968 NULL, NULL,
1969 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970 if (fname != NULL)
1971 {
1972 cmd_source(fname, eap);
1973 vim_free(fname);
1974 }
1975 }
1976 else
1977#endif
1978 cmd_source(eap->arg, eap);
1979}
1980
1981 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001982cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983{
1984 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001985 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001988 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00001989 * Need to execute the commands directly. This is required at least
1990 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001991 * - ":g" command busy
1992 * - after ":argdo", ":windo" or ":bufdo"
1993 * - another command follows
1994 * - inside a loop
1995 */
1996 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
1997#ifdef FEAT_EVAL
1998 || eap->cstack->cs_idx >= 0
1999#endif
2000 );
2001
2002 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002003 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002004 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005}
2006
2007/*
2008 * ":source" and associated commands.
2009 */
2010/*
2011 * Structure used to store info for each sourced file.
2012 * It is shared between do_source() and getsourceline().
2013 * This is required, because it needs to be handed to do_cmdline() and
2014 * sourcing can be done recursively.
2015 */
2016struct source_cookie
2017{
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002018 FILE *fp; // opened file for sourcing
2019 char_u *nextline; // if not NULL: line that was read ahead
2020 linenr_T sourcing_lnum; // line number of the source file
2021 int finished; // ":finish" used
Bram Moolenaar00590742019-02-15 21:06:09 +01002022#ifdef USE_CRNL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002023 int fileformat; // EOL_UNKNOWN, EOL_UNIX or EOL_DOS
2024 int error; // TRUE if LF found after CR-LF
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025#endif
2026#ifdef FEAT_EVAL
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002027 linenr_T breakpoint; // next line with breakpoint or zero
2028 char_u *fname; // name of sourced file
2029 int dbg_tick; // debug_tick when breakpoint was set
2030 int level; // top nesting level of sourced file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002032 vimconv_T conv; // type of conversion
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033};
2034
2035#ifdef FEAT_EVAL
2036/*
2037 * Return the address holding the next breakpoint line for a source cookie.
2038 */
2039 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002040source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041{
2042 return &((struct source_cookie *)cookie)->breakpoint;
2043}
2044
2045/*
2046 * Return the address holding the debug tick for a source cookie.
2047 */
2048 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002049source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050{
2051 return &((struct source_cookie *)cookie)->dbg_tick;
2052}
2053
2054/*
2055 * Return the nesting level for a source cookie.
2056 */
2057 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002058source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059{
2060 return ((struct source_cookie *)cookie)->level;
2061}
2062#endif
2063
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002064static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065
Bram Moolenaar4f974752019-02-17 17:44:42 +01002066#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002067# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068/*
2069 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002070 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071 */
2072 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002073fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074{
Bram Moolenaar4f974752019-02-17 17:44:42 +01002075# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01002076 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
2077# else
2078 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002079# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080
2081 if (fd_tmp == -1)
2082 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002083
2084# ifdef HAVE_FD_CLOEXEC
2085 {
2086 int fdflags = fcntl(fd_tmp, F_GETFD);
2087 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02002088 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002089 }
2090# endif
2091
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092 return fdopen(fd_tmp, READBIN);
2093}
2094#endif
2095
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096/*
2097 * do_source: Read the file "fname" and execute its lines as EX commands.
2098 *
2099 * This function may be called recursively!
2100 *
2101 * return FAIL if file could not be opened, OK otherwise
2102 */
2103 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002104do_source(
2105 char_u *fname,
2106 int check_other, /* check for .vimrc and _vimrc */
2107 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002108{
2109 struct source_cookie cookie;
2110 char_u *save_sourcing_name;
2111 linenr_T save_sourcing_lnum;
2112 char_u *p;
2113 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00002114 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115 int retval = FAIL;
2116#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002117 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002119 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002120 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002121 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002122 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002123# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02002124 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002125 int stat_ok;
2126# endif
2127#endif
2128#ifdef STARTUPTIME
2129 struct timeval tv_rel;
2130 struct timeval tv_start;
2131#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002132#ifdef FEAT_PROFILE
2133 proftime_T wait_start;
2134#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002135 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 if (p == NULL)
2139 return retval;
2140 fname_exp = fix_fname(p);
2141 vim_free(p);
2142 if (fname_exp == NULL)
2143 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144 if (mch_isdir(fname_exp))
2145 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002146 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 goto theend;
2148 }
2149
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002150 /* Apply SourceCmd autocommands, they should get the file and source it. */
2151 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
2152 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
2153 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002154 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002155#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002156 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002157#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002158 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002159#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01002160 if (retval == OK)
2161 // Apply SourcePost autocommands.
2162 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
2163 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00002164 goto theend;
2165 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00002166
2167 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002168 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002169
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002170#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2172#else
2173 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2174#endif
2175 if (cookie.fp == NULL && check_other)
2176 {
2177 /*
2178 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2179 * and ".exrc" by "_exrc" or vice versa.
2180 */
2181 p = gettail(fname_exp);
2182 if ((*p == '.' || *p == '_')
2183 && (STRICMP(p + 1, "vimrc") == 0
2184 || STRICMP(p + 1, "gvimrc") == 0
2185 || STRICMP(p + 1, "exrc") == 0))
2186 {
2187 if (*p == '_')
2188 *p = '.';
2189 else
2190 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002191#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002192 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2193#else
2194 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2195#endif
2196 }
2197 }
2198
2199 if (cookie.fp == NULL)
2200 {
2201 if (p_verbose > 0)
2202 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002203 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002205 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002207 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002208 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002209 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002210 }
2211 goto theend;
2212 }
2213
2214 /*
2215 * The file exists.
2216 * - In verbose mode, give a message.
2217 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2218 */
2219 if (p_verbose > 1)
2220 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002221 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002222 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002223 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002225 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00002226 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002227 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002229 if (is_vimrc == DOSO_VIMRC)
2230 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
2231 else if (is_vimrc == DOSO_GVIMRC)
2232 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233
2234#ifdef USE_CRNL
2235 /* If no automatic file format: Set default to CR-NL. */
2236 if (*p_ffs == NUL)
2237 cookie.fileformat = EOL_DOS;
2238 else
2239 cookie.fileformat = EOL_UNKNOWN;
2240 cookie.error = FALSE;
2241#endif
2242
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243 cookie.nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002244 cookie.sourcing_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245 cookie.finished = FALSE;
2246
2247#ifdef FEAT_EVAL
2248 /*
2249 * Check if this script has a breakpoint.
2250 */
2251 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2252 cookie.fname = fname_exp;
2253 cookie.dbg_tick = debug_tick;
2254
2255 cookie.level = ex_nesting_level;
2256#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257
2258 /*
2259 * Keep the sourcing name/lnum, for recursive calls.
2260 */
2261 save_sourcing_name = sourcing_name;
2262 sourcing_name = fname_exp;
2263 save_sourcing_lnum = sourcing_lnum;
2264 sourcing_lnum = 0;
2265
2266#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01002267 if (time_fd != NULL)
2268 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269#endif
2270
2271#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00002272# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002273 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002274 prof_child_enter(&wait_start); /* entering a child now */
2275# endif
2276
2277 /* Don't use local function variables, if called from a function.
2278 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002279 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002280
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002281 save_current_sctx = current_sctx;
2282 current_sctx.sc_lnum = 0;
2283 current_sctx.sc_version = 1;
2284
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002285 // Check if this script was sourced before to finds its SID.
2286 // If it's new, generate a new SID.
2287 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01002288 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289# ifdef UNIX
2290 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2291# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002292 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
2293 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002294 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002295 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002296 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 && (
2298# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00002299 /* Compare dev/ino when possible, it catches symbolic
2300 * links. Also compare file names, the inode may change
2301 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002302 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002303 && (si->sn_dev == st.st_dev
2304 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00002306 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002308 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002309 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002311 current_sctx.sc_sid = ++last_current_SID;
2312 if (ga_grow(&script_items,
2313 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002314 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002315 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002317 ++script_items.ga_len;
2318 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
2319# ifdef FEAT_PROFILE
2320 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002323 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002324 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01002325 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00002326# ifdef UNIX
2327 if (stat_ok)
2328 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002329 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002330 si->sn_dev = st.st_dev;
2331 si->sn_ino = st.st_ino;
2332 }
2333 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00002334 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002335# endif
2336
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002338 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 }
2340
Bram Moolenaar05159a02005-02-26 23:04:13 +00002341# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002342 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002343 {
2344 int forceit;
2345
2346 /* Check if we do profiling for this script. */
2347 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
2348 {
2349 script_do_profile(si);
2350 si->sn_pr_force = forceit;
2351 }
2352 if (si->sn_prof_on)
2353 {
2354 ++si->sn_pr_count;
2355 profile_start(&si->sn_pr_start);
2356 profile_zero(&si->sn_pr_children);
2357 }
2358 }
2359# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360#endif
2361
Bram Moolenaar67435d92017-10-19 21:04:37 +02002362 cookie.conv.vc_type = CONV_NONE; /* no conversion */
2363
2364 /* Read the first line so we can check for a UTF-8 BOM. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02002365 firstline = getsourceline(0, (void *)&cookie, 0, TRUE);
Bram Moolenaar67435d92017-10-19 21:04:37 +02002366 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
2367 && firstline[1] == 0xbb && firstline[2] == 0xbf)
2368 {
2369 /* Found BOM; setup conversion, skip over BOM and recode the line. */
2370 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
2371 p = string_convert(&cookie.conv, firstline + 3, NULL);
2372 if (p == NULL)
2373 p = vim_strsave(firstline + 3);
2374 if (p != NULL)
2375 {
2376 vim_free(firstline);
2377 firstline = p;
2378 }
2379 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02002380
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 /*
2382 * Call do_cmdline, which will call getsourceline() to get the lines.
2383 */
Bram Moolenaar73881402009-02-04 16:50:47 +00002384 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002387
2388#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002389 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002390 {
2391 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002392 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002393 if (si->sn_prof_on)
2394 {
2395 profile_end(&si->sn_pr_start);
2396 profile_sub_wait(&wait_start, &si->sn_pr_start);
2397 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00002398 profile_self(&si->sn_pr_self, &si->sn_pr_start,
2399 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002400 }
2401 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402#endif
2403
2404 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002405 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 sourcing_name = save_sourcing_name;
2407 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 if (p_verbose > 1)
2409 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002410 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002411 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002413 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002414 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 }
2416#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01002417 if (time_fd != NULL)
2418 {
2419 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
2420 time_msg((char *)IObuff, &tv_start);
2421 time_pop(&tv_rel);
2422 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002423#endif
2424
Bram Moolenaar2b618522019-01-12 13:26:03 +01002425 if (!got_int)
2426 trigger_source_post = TRUE;
2427
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428#ifdef FEAT_EVAL
2429 /*
2430 * After a "finish" in debug mode, need to break at first command of next
2431 * sourced file.
2432 */
2433 if (save_debug_break_level > ex_nesting_level
2434 && debug_break_level == ex_nesting_level)
2435 ++debug_break_level;
2436#endif
2437
Bram Moolenaar05159a02005-02-26 23:04:13 +00002438#ifdef FEAT_EVAL
2439almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002440 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02002441 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00002442# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002443 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002444 prof_child_exit(&wait_start); /* leaving a child now */
2445# endif
2446#endif
2447 fclose(cookie.fp);
2448 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00002449 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002450 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002451
Bram Moolenaar2b618522019-01-12 13:26:03 +01002452 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01002453 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01002454
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455theend:
2456 vim_free(fname_exp);
2457 return retval;
2458}
2459
2460#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00002461
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462/*
2463 * ":scriptnames"
2464 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002465 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01002466ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467{
2468 int i;
2469
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01002470 if (eap->addr_count > 0)
2471 {
2472 // :script {scriptId}: edit the script
2473 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002474 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01002475 else
2476 {
2477 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
2478 do_exedit(eap, NULL);
2479 }
2480 return;
2481 }
2482
Bram Moolenaar05159a02005-02-26 23:04:13 +00002483 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
2484 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02002485 {
2486 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
2487 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002488 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002489 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002490}
2491
2492# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
2493/*
2494 * Fix slashes in the list of script names for 'shellslash'.
2495 */
2496 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002497scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498{
2499 int i;
2500
Bram Moolenaar05159a02005-02-26 23:04:13 +00002501 for (i = 1; i <= script_items.ga_len; ++i)
2502 if (SCRIPT_ITEM(i).sn_name != NULL)
2503 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504}
2505# endif
2506
2507/*
2508 * Get a pointer to a script name. Used for ":verbose set".
2509 */
2510 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002511get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512{
2513 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002514 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002516 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002518 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002520 return (char_u *)_("environment variable");
2521 if (id == SID_ERROR)
2522 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00002523 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002524}
Bram Moolenaar05159a02005-02-26 23:04:13 +00002525
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00002526# if defined(EXITFREE) || defined(PROTO)
2527 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002528free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00002529{
2530 int i;
2531
2532 for (i = script_items.ga_len; i > 0; --i)
2533 vim_free(SCRIPT_ITEM(i).sn_name);
2534 ga_clear(&script_items);
2535}
2536# endif
2537
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538#endif
2539
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002540 linenr_T
2541get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), void *cookie)
2542{
2543 return fgetline == getsourceline
2544 ? ((struct source_cookie *)cookie)->sourcing_lnum
2545 : sourcing_lnum;
2546}
2547
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548/*
2549 * Get one full line from a sourced file.
2550 * Called by do_cmdline() when it's called from do_source().
2551 *
2552 * Return a pointer to the line in allocated memory.
2553 * Return NULL for end-of-file or some error.
2554 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555 char_u *
Bram Moolenaare96a2492019-06-25 04:12:16 +02002556getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557{
2558 struct source_cookie *sp = (struct source_cookie *)cookie;
2559 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01002560 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561
2562#ifdef FEAT_EVAL
2563 /* If breakpoints have been added/deleted need to check for it. */
2564 if (sp->dbg_tick < debug_tick)
2565 {
2566 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
2567 sp->dbg_tick = debug_tick;
2568 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00002569# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002570 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002571 script_line_end();
2572# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573#endif
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002574
2575 // Set the current sourcing line number.
2576 sourcing_lnum = sp->sourcing_lnum + 1;
2577
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578 /*
2579 * Get current line. If there is a read-ahead line, use it, otherwise get
2580 * one now.
2581 */
2582 if (sp->finished)
2583 line = NULL;
2584 else if (sp->nextline == NULL)
2585 line = get_one_sourceline(sp);
2586 else
2587 {
2588 line = sp->nextline;
2589 sp->nextline = NULL;
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002590 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00002592#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00002593 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00002594 script_line_start();
2595#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596
2597 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
2598 * contain the 'C' flag. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02002599 if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600 {
2601 /* compensate for the one line read-ahead */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002602 --sp->sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01002603
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02002604 // Get the next line and concatenate it when it starts with a
2605 // backslash. We always need to read the next line, keep it in
2606 // sp->nextline.
2607 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01002608 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02002609 if (sp->nextline != NULL
2610 && (*(p = skipwhite(sp->nextline)) == '\\'
2611 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01002613 garray_T ga;
2614
Bram Moolenaarb549a732012-02-22 18:29:33 +01002615 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01002616 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02002617 if (*p == '\\')
2618 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01002619 for (;;)
2620 {
2621 vim_free(sp->nextline);
2622 sp->nextline = get_one_sourceline(sp);
2623 if (sp->nextline == NULL)
2624 break;
2625 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02002626 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01002627 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02002628 // Adjust the growsize to the current length to speed up
2629 // concatenating many lines.
2630 if (ga.ga_len > 400)
2631 {
2632 if (ga.ga_len > 8000)
2633 ga.ga_growsize = 8000;
2634 else
2635 ga.ga_growsize = ga.ga_len;
2636 }
2637 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01002638 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02002639 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
2640 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01002641 }
2642 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01002644 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 }
2646 }
2647
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 if (line != NULL && sp->conv.vc_type != CONV_NONE)
2649 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01002650 char_u *s;
2651
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 /* Convert the encoding of the script line. */
2653 s = string_convert(&sp->conv, line, NULL);
2654 if (s != NULL)
2655 {
2656 vim_free(line);
2657 line = s;
2658 }
2659 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660
2661#ifdef FEAT_EVAL
2662 /* Did we encounter a breakpoint? */
2663 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
2664 {
2665 dbg_breakpoint(sp->fname, sourcing_lnum);
2666 /* Find next breakpoint. */
2667 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
2668 sp->dbg_tick = debug_tick;
2669 }
2670#endif
2671
2672 return line;
2673}
2674
2675 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002676get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677{
2678 garray_T ga;
2679 int len;
2680 int c;
2681 char_u *buf;
2682#ifdef USE_CRNL
2683 int has_cr; /* CR-LF found */
2684#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 int have_read = FALSE;
2686
2687 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002688 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689
2690 /*
2691 * Loop until there is a finished line (or end-of-file).
2692 */
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002693 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694 for (;;)
2695 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002696 /* make room to read at least 120 (more) characters */
2697 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 break;
2699 buf = (char_u *)ga.ga_data;
2700
Bram Moolenaar00590742019-02-15 21:06:09 +01002701 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00002702 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01002703 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002704 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705#ifdef USE_CRNL
2706 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
2707 * CTRL-Z by its own, or after a NL. */
2708 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
2709 && sp->fileformat == EOL_DOS
2710 && buf[len - 1] == Ctrl_Z)
2711 {
2712 buf[len - 1] = NUL;
2713 break;
2714 }
2715#endif
2716
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 ga.ga_len = len;
2719
2720 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002721 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 continue;
2723
2724 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
2725 {
2726#ifdef USE_CRNL
2727 has_cr = (len >= 2 && buf[len - 2] == '\r');
2728 if (sp->fileformat == EOL_UNKNOWN)
2729 {
2730 if (has_cr)
2731 sp->fileformat = EOL_DOS;
2732 else
2733 sp->fileformat = EOL_UNIX;
2734 }
2735
2736 if (sp->fileformat == EOL_DOS)
2737 {
2738 if (has_cr) /* replace trailing CR */
2739 {
2740 buf[len - 2] = '\n';
2741 --len;
2742 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 }
2744 else /* lines like ":map xx yy^M" will have failed */
2745 {
2746 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002747 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01002748 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002749 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002750 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751 sp->error = TRUE;
2752 sp->fileformat = EOL_UNIX;
2753 }
2754 }
2755#endif
2756 /* The '\n' is escaped if there is an odd number of ^V's just
2757 * before it, first set "c" just before the 'V's and then check
2758 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
2759 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
2760 ;
2761 if ((len & 1) != (c & 1)) /* escaped NL, read more */
2762 {
Bram Moolenaarbc2cfe42019-07-04 14:57:12 +02002763 ++sp->sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 continue;
2765 }
2766
2767 buf[len - 1] = NUL; /* remove the NL */
2768 }
2769
2770 /*
2771 * Check for ^C here now and then, so recursive :so can be broken.
2772 */
2773 line_breakcheck();
2774 break;
2775 }
2776
2777 if (have_read)
2778 return (char_u *)ga.ga_data;
2779
2780 vim_free(ga.ga_data);
2781 return NULL;
2782}
2783
2784/*
2785 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002788ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002789{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790 struct source_cookie *sp;
2791 char_u *name;
2792
2793 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
2794 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002795 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796 return;
2797 }
2798
2799 if (*eap->arg != NUL)
2800 {
2801 name = enc_canonize(eap->arg);
2802 if (name == NULL) /* out of memory */
2803 return;
2804 }
2805 else
2806 name = eap->arg;
2807
2808 /* Setup for conversion from the specified encoding to 'encoding'. */
2809 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
2810 convert_setup(&sp->conv, name, p_enc);
2811
2812 if (name != eap->arg)
2813 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814}
2815
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002816/*
2817 * ":scriptversion": Set Vim script version for a sourced script.
2818 */
2819 void
2820ex_scriptversion(exarg_T *eap UNUSED)
2821{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02002822#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002823 int nr;
2824
2825 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
2826 {
2827 emsg(_("E984: :scriptversion used outside of a sourced file"));
2828 return;
2829 }
2830
2831 nr = getdigits(&eap->arg);
2832 if (nr == 0 || *eap->arg != NUL)
2833 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02002834 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002835 semsg(_("E999: scriptversion not supported: %d"), nr);
2836 else
2837 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02002838#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02002839}
2840
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841#if defined(FEAT_EVAL) || defined(PROTO)
2842/*
2843 * ":finish": Mark a sourced file as finished.
2844 */
2845 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002846ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847{
2848 if (getline_equal(eap->getline, eap->cookie, getsourceline))
2849 do_finish(eap, FALSE);
2850 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002851 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852}
2853
2854/*
2855 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
2856 * Also called for a pending finish at the ":endtry" or after returning from
2857 * an extra do_cmdline(). "reanimate" is used in the latter case.
2858 */
2859 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002860do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861{
2862 int idx;
2863
2864 if (reanimate)
2865 ((struct source_cookie *)getline_cookie(eap->getline,
2866 eap->cookie))->finished = FALSE;
2867
2868 /*
2869 * Cleanup (and inactivate) conditionals, but stop when a try conditional
2870 * not in its finally clause (which then is to be executed next) is found.
2871 * In this case, make the ":finish" pending for execution at the ":endtry".
2872 * Otherwise, finish normally.
2873 */
2874 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
2875 if (idx >= 0)
2876 {
2877 eap->cstack->cs_pending[idx] = CSTP_FINISH;
2878 report_make_pending(CSTP_FINISH, NULL);
2879 }
2880 else
2881 ((struct source_cookie *)getline_cookie(eap->getline,
2882 eap->cookie))->finished = TRUE;
2883}
2884
2885
2886/*
2887 * Return TRUE when a sourced file had the ":finish" command: Don't give error
2888 * message for missing ":endif".
2889 * Return FALSE when not sourcing a file.
2890 */
2891 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002892source_finished(
Bram Moolenaare96a2492019-06-25 04:12:16 +02002893 char_u *(*fgetline)(int, void *, int, int),
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002894 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895{
Bram Moolenaar89d40322006-08-29 15:30:07 +00002896 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00002898 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899}
2900#endif
2901
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902/*
2903 * ":checktime [buffer]"
2904 */
2905 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002906ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907{
2908 buf_T *buf;
2909 int save_no_check_timestamps = no_check_timestamps;
2910
2911 no_check_timestamps = 0;
2912 if (eap->addr_count == 0) /* default is all buffers */
2913 check_timestamps(FALSE);
2914 else
2915 {
2916 buf = buflist_findnr((int)eap->line2);
2917 if (buf != NULL) /* cannot happen? */
2918 (void)buf_check_timestamp(buf, FALSE);
2919 }
2920 no_check_timestamps = save_no_check_timestamps;
2921}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
2924 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02002925# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01002926 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002927get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01002929 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930
Bram Moolenaar48e330a2016-02-23 14:53:34 +01002931 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01002932 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933
Bram Moolenaar4f974752019-02-17 17:44:42 +01002934# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935 if (loc != NULL)
2936 {
2937 char_u *p;
2938
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002939 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
2940 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 p = vim_strchr(loc, '=');
2942 if (p != NULL)
2943 {
2944 loc = ++p;
2945 while (*p != NUL) /* remove trailing newline */
2946 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002947 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948 {
2949 *p = NUL;
2950 break;
2951 }
2952 ++p;
2953 }
2954 }
2955 }
2956# endif
2957
2958 return loc;
2959}
2960#endif
2961
2962
Bram Moolenaar4f974752019-02-17 17:44:42 +01002963#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964/*
2965 * On MS-Windows locale names are strings like "German_Germany.1252", but
2966 * gettext expects "de". Try to translate one into another here for a few
2967 * supported languages.
2968 */
2969 static char_u *
2970gettext_lang(char_u *name)
2971{
2972 int i;
2973 static char *(mtable[]) = {
2974 "afrikaans", "af",
2975 "czech", "cs",
2976 "dutch", "nl",
2977 "german", "de",
2978 "english_united kingdom", "en_GB",
2979 "spanish", "es",
2980 "french", "fr",
2981 "italian", "it",
2982 "japanese", "ja",
2983 "korean", "ko",
2984 "norwegian", "no",
2985 "polish", "pl",
2986 "russian", "ru",
2987 "slovak", "sk",
2988 "swedish", "sv",
2989 "ukrainian", "uk",
2990 "chinese_china", "zh_CN",
2991 "chinese_taiwan", "zh_TW",
2992 NULL};
2993
2994 for (i = 0; mtable[i] != NULL; i += 2)
2995 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01002996 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997 return name;
2998}
2999#endif
3000
3001#if defined(FEAT_MULTI_LANG) || defined(PROTO)
3002/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01003003 * Return TRUE when "lang" starts with a valid language name.
3004 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
3005 */
3006 static int
3007is_valid_mess_lang(char_u *lang)
3008{
3009 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
3010}
3011
3012/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003013 * Obtain the current messages language. Used to set the default for
3014 * 'helplang'. May return NULL or an empty string.
3015 */
3016 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003017get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018{
3019 char_u *p;
3020
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003021# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003023 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003024# else
3025 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00003026 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
3027 * and LC_MONETARY may be set differently for a Japanese working in the
3028 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003029 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030# endif
3031# else
3032 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003033 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 {
3035 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01003036 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 p = mch_getenv((char_u *)"LANG");
3038 }
3039# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003040# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041 p = gettext_lang(p);
3042# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01003043 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044}
3045#endif
3046
Bram Moolenaardef9e822004-12-31 20:58:58 +00003047/* Complicated #if; matches with where get_mess_env() is used below. */
3048#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3049 && defined(LC_MESSAGES))) \
3050 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00003051 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052/*
3053 * Get the language used for messages from the environment.
3054 */
3055 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003056get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057{
3058 char_u *p;
3059
3060 p = mch_getenv((char_u *)"LC_ALL");
3061 if (p == NULL || *p == NUL)
3062 {
3063 p = mch_getenv((char_u *)"LC_MESSAGES");
3064 if (p == NULL || *p == NUL)
3065 {
3066 p = mch_getenv((char_u *)"LANG");
3067 if (p != NULL && VIM_ISDIGIT(*p))
3068 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003069# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003071 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072# endif
3073 }
3074 }
3075 return p;
3076}
3077#endif
3078
3079#if defined(FEAT_EVAL) || defined(PROTO)
3080
3081/*
3082 * Set the "v:lang" variable according to the current locale setting.
3083 * Also do "v:lc_time"and "v:ctype".
3084 */
3085 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003086set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087{
3088 char_u *loc;
3089
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003090# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003091 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092# else
3093 /* setlocale() not supported: use the default value */
3094 loc = (char_u *)"C";
3095# endif
3096 set_vim_var_string(VV_CTYPE, loc, -1);
3097
3098 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
3099 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003100# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003101 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102# else
3103 loc = get_mess_env();
3104# endif
3105 set_vim_var_string(VV_LANG, loc, -1);
3106
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003107# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01003108 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109# endif
3110 set_vim_var_string(VV_LC_TIME, loc, -1);
3111}
3112#endif
3113
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01003114#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115/*
3116 * ":language": Set the language (locale).
3117 */
3118 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003119ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120{
3121 char *loc;
3122 char_u *p;
3123 char_u *name;
3124 int what = LC_ALL;
3125 char *whatstr = "";
3126#ifdef LC_MESSAGES
3127# define VIM_LC_MESSAGES LC_MESSAGES
3128#else
3129# define VIM_LC_MESSAGES 6789
3130#endif
3131
3132 name = eap->arg;
3133
3134 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
3135 * Allow abbreviation, but require at least 3 characters to avoid
3136 * confusion with a two letter language name "me" or "ct". */
3137 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003138 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 {
3140 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
3141 {
3142 what = VIM_LC_MESSAGES;
3143 name = skipwhite(p);
3144 whatstr = "messages ";
3145 }
3146 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
3147 {
3148 what = LC_CTYPE;
3149 name = skipwhite(p);
3150 whatstr = "ctype ";
3151 }
3152 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
3153 {
3154 what = LC_TIME;
3155 name = skipwhite(p);
3156 whatstr = "time ";
3157 }
3158 }
3159
3160 if (*name == NUL)
3161 {
3162#ifndef LC_MESSAGES
3163 if (what == VIM_LC_MESSAGES)
3164 p = get_mess_env();
3165 else
3166#endif
3167 p = (char_u *)setlocale(what, NULL);
3168 if (p == NULL || *p == NUL)
3169 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003170 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171 }
3172 else
3173 {
3174#ifndef LC_MESSAGES
3175 if (what == VIM_LC_MESSAGES)
3176 loc = "";
3177 else
3178#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003179 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003181#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
3182 /* Make sure strtod() uses a decimal point, not a comma. */
3183 setlocale(LC_NUMERIC, "C");
3184#endif
3185 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003187 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188 else
3189 {
3190#ifdef HAVE_NL_MSG_CAT_CNTR
3191 /* Need to do this for GNU gettext, otherwise cached translations
3192 * will be used again. */
3193 extern int _nl_msg_cat_cntr;
3194
3195 ++_nl_msg_cat_cntr;
3196#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00003197 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
3199
3200 if (what != LC_TIME)
3201 {
3202 /* Tell gettext() what to translate to. It apparently doesn't
3203 * use the currently effective locale. Also do this when
3204 * FEAT_GETTEXT isn't defined, so that shell commands use this
3205 * value. */
3206 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003207 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02003209
3210 /* Clear $LANGUAGE because GNU gettext uses it. */
3211 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01003212# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00003213 /* Apparently MS-Windows printf() may cause a crash when
3214 * we give it 8-bit text while it's expecting text in the
3215 * current locale. This call avoids that. */
3216 setlocale(LC_CTYPE, "C");
3217# endif
3218 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219 if (what != LC_CTYPE)
3220 {
3221 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003222#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223 mname = gettext_lang(name);
3224#else
3225 mname = name;
3226#endif
3227 vim_setenv((char_u *)"LC_MESSAGES", mname);
3228#ifdef FEAT_MULTI_LANG
3229 set_helplang_default(mname);
3230#endif
3231 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232 }
3233
3234# ifdef FEAT_EVAL
3235 /* Set v:lang, v:lc_time and v:ctype to the final result. */
3236 set_lang_var();
3237# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02003238# ifdef FEAT_TITLE
3239 maketitle();
3240# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 }
3242 }
3243}
3244
3245# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003246
3247static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003248
Bram Moolenaar4f974752019-02-17 17:44:42 +01003249# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003250static int did_init_locales = FALSE;
3251
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003252/* Return an array of strings for all available locales + NULL for the
3253 * last element. Return NULL in case of error. */
3254 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003255find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003256{
3257 garray_T locales_ga;
3258 char_u *loc;
3259
3260 /* Find all available locales by running command "locale -a". If this
3261 * doesn't work we won't have completion. */
3262 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02003263 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003264 if (locale_a == NULL)
3265 return NULL;
3266 ga_init2(&locales_ga, sizeof(char_u *), 20);
3267
3268 /* Transform locale_a string where each locale is separated by "\n"
3269 * into an array of locale strings. */
3270 loc = (char_u *)strtok((char *)locale_a, "\n");
3271
3272 while (loc != NULL)
3273 {
3274 if (ga_grow(&locales_ga, 1) == FAIL)
3275 break;
3276 loc = vim_strsave(loc);
3277 if (loc == NULL)
3278 break;
3279
3280 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
3281 loc = (char_u *)strtok(NULL, "\n");
3282 }
3283 vim_free(locale_a);
3284 if (ga_grow(&locales_ga, 1) == FAIL)
3285 {
3286 ga_clear(&locales_ga);
3287 return NULL;
3288 }
3289 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
3290 return (char_u **)locales_ga.ga_data;
3291}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003292# endif
3293
3294/*
3295 * Lazy initialization of all available locales.
3296 */
3297 static void
3298init_locales(void)
3299{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003300# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01003301 if (!did_init_locales)
3302 {
3303 did_init_locales = TRUE;
3304 locales = find_locales();
3305 }
3306# endif
3307}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003308
3309# if defined(EXITFREE) || defined(PROTO)
3310 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003311free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003312{
3313 int i;
3314 if (locales != NULL)
3315 {
3316 for (i = 0; locales[i] != NULL; i++)
3317 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01003318 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003319 }
3320}
3321# endif
3322
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323/*
3324 * Function given to ExpandGeneric() to obtain the possible arguments of the
3325 * ":language" command.
3326 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003328get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329{
3330 if (idx == 0)
3331 return (char_u *)"messages";
3332 if (idx == 1)
3333 return (char_u *)"ctype";
3334 if (idx == 2)
3335 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003336
3337 init_locales();
3338 if (locales == NULL)
3339 return NULL;
3340 return locales[idx - 3];
3341}
3342
3343/*
3344 * Function given to ExpandGeneric() to obtain the available locales.
3345 */
3346 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003347get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02003348{
3349 init_locales();
3350 if (locales == NULL)
3351 return NULL;
3352 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353}
3354# endif
3355
3356#endif