blob: 2537e8d7b4ae912323aac24ef9577aaa2fd74778 [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
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar433f7c82006-03-21 21:29:36 +000069# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +000070/*
71 * Store the current time in "tm".
72 */
73 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010074profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +000075{
Bram Moolenaar4f974752019-02-17 17:44:42 +010076# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000077 QueryPerformanceCounter(tm);
78# else
Bram Moolenaar05159a02005-02-26 23:04:13 +000079 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000080# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +000081}
82
83/*
84 * Compute the elapsed time from "tm" till now and store in "tm".
85 */
86 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010087profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +000088{
89 proftime_T now;
90
Bram Moolenaar4f974752019-02-17 17:44:42 +010091# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000092 QueryPerformanceCounter(&now);
93 tm->QuadPart = now.QuadPart - tm->QuadPart;
94# else
Bram Moolenaar05159a02005-02-26 23:04:13 +000095 gettimeofday(&now, NULL);
96 tm->tv_usec = now.tv_usec - tm->tv_usec;
97 tm->tv_sec = now.tv_sec - tm->tv_sec;
98 if (tm->tv_usec < 0)
99 {
100 tm->tv_usec += 1000000;
101 --tm->tv_sec;
102 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000103# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000104}
105
106/*
107 * Subtract the time "tm2" from "tm".
108 */
109 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100110profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000111{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100112# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000113 tm->QuadPart -= tm2->QuadPart;
114# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000115 tm->tv_usec -= tm2->tv_usec;
116 tm->tv_sec -= tm2->tv_sec;
117 if (tm->tv_usec < 0)
118 {
119 tm->tv_usec += 1000000;
120 --tm->tv_sec;
121 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000122# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000123}
124
125/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000126 * Return a string that represents the time in "tm".
127 * Uses a static buffer!
128 */
129 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100130profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000131{
132 static char buf[50];
133
Bram Moolenaar4f974752019-02-17 17:44:42 +0100134# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000135 LARGE_INTEGER fr;
136
137 QueryPerformanceFrequency(&fr);
138 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
139# else
140 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000141# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000142 return buf;
143}
144
Bram Moolenaar79c2c882016-02-07 21:19:28 +0100145# if defined(FEAT_FLOAT) || defined(PROTO)
146/*
147 * Return a float that represents the time in "tm".
148 */
149 float_T
150profile_float(proftime_T *tm)
151{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100152# ifdef MSWIN
Bram Moolenaar79c2c882016-02-07 21:19:28 +0100153 LARGE_INTEGER fr;
154
155 QueryPerformanceFrequency(&fr);
156 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
157# else
158 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
159# endif
160}
161# endif
162
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000163/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000164 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000165 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000166 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100167profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +0000168{
169 if (msec <= 0) /* no limit */
170 profile_zero(tm);
171 else
172 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100173# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +0000174 LARGE_INTEGER fr;
175
176 QueryPerformanceCounter(tm);
177 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000178 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000179# else
180 long usec;
181
182 gettimeofday(tm, NULL);
183 usec = (long)tm->tv_usec + (long)msec * 1000;
184 tm->tv_usec = usec % 1000000L;
185 tm->tv_sec += usec / 1000000L;
186# endif
187 }
188}
189
190/*
191 * Return TRUE if the current time is past "tm".
192 */
193 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100194profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +0000195{
196 proftime_T now;
197
Bram Moolenaar4f974752019-02-17 17:44:42 +0100198# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +0000199 if (tm->QuadPart == 0) /* timer was not set */
200 return FALSE;
201 QueryPerformanceCounter(&now);
202 return (now.QuadPart > tm->QuadPart);
203# else
204 if (tm->tv_sec == 0) /* timer was not set */
205 return FALSE;
206 gettimeofday(&now, NULL);
207 return (now.tv_sec > tm->tv_sec
208 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
209# endif
210}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000211
212/*
213 * Set the time in "tm" to zero.
214 */
215 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100216profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000217{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100218# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000219 tm->QuadPart = 0;
220# else
221 tm->tv_usec = 0;
222 tm->tv_sec = 0;
223# endif
224}
225
Bram Moolenaar76929292008-01-06 19:07:36 +0000226# endif /* FEAT_PROFILE || FEAT_RELTIME */
227
Bram Moolenaar975b5272016-03-15 23:10:59 +0100228# if defined(FEAT_TIMERS) || defined(PROTO)
229static timer_T *first_timer = NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200230static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100231
Bram Moolenaar2f106582019-05-08 21:59:25 +0200232/*
233 * Return time left until "due". Negative if past "due".
234 */
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200235 long
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100236proftime_time_left(proftime_T *due, proftime_T *now)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200237{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100238# ifdef MSWIN
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200239 LARGE_INTEGER fr;
240
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100241 if (now->QuadPart > due->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200242 return 0;
243 QueryPerformanceFrequency(&fr);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100244 return (long)(((double)(due->QuadPart - now->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200245 / (double)fr.QuadPart) * 1000);
246# else
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100247 if (now->tv_sec > due->tv_sec)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200248 return 0;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100249 return (due->tv_sec - now->tv_sec) * 1000
250 + (due->tv_usec - now->tv_usec) / 1000;
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200251# endif
252}
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200253
Bram Moolenaar975b5272016-03-15 23:10:59 +0100254/*
255 * Insert a timer in the list of timers.
256 */
257 static void
258insert_timer(timer_T *timer)
259{
260 timer->tr_next = first_timer;
261 timer->tr_prev = NULL;
262 if (first_timer != NULL)
263 first_timer->tr_prev = timer;
264 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +0200265 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100266}
267
268/*
269 * Take a timer out of the list of timers.
270 */
271 static void
272remove_timer(timer_T *timer)
273{
274 if (timer->tr_prev == NULL)
275 first_timer = timer->tr_next;
276 else
277 timer->tr_prev->tr_next = timer->tr_next;
278 if (timer->tr_next != NULL)
279 timer->tr_next->tr_prev = timer->tr_prev;
280}
281
282 static void
283free_timer(timer_T *timer)
284{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200285 free_callback(&timer->tr_callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200286 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100287}
288
289/*
290 * Create a timer and return it. NULL if out of memory.
291 * Caller should set the callback.
292 */
293 timer_T *
294create_timer(long msec, int repeat)
295{
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200296 timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
Bram Moolenaaree39ef02016-09-10 19:17:42 +0200297 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100298
299 if (timer == NULL)
300 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +0200301 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200302 /* Overflow! Might cause duplicates... */
303 last_timer_id = 0;
304 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100305 insert_timer(timer);
306 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100307 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200308 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100309
310 profile_setlimit(msec, &timer->tr_due);
311 return timer;
312}
313
314/*
315 * Invoke the callback of "timer".
316 */
317 static void
318timer_callback(timer_T *timer)
319{
320 typval_T rettv;
321 int dummy;
322 typval_T argv[2];
323
324 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200325 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100326 argv[1].v_type = VAR_UNKNOWN;
327
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200328 call_callback(&timer->tr_callback, -1,
329 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100330 clear_tv(&rettv);
331}
332
333/*
334 * Call timers that are due.
335 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200336 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100337 */
338 long
Bram Moolenaarcf089462016-06-12 21:18:43 +0200339check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100340{
341 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200342 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100343 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +0100344 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100345 proftime_T now;
346 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200347 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200348 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100349
Bram Moolenaarc577d812017-07-08 22:37:34 +0200350 /* Don't run any timers while exiting or dealing with an error. */
351 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200352 return next_due;
353
Bram Moolenaar75537a92016-09-05 22:45:28 +0200354 profile_start(&now);
355 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100356 {
Bram Moolenaar75537a92016-09-05 22:45:28 +0200357 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200358
Bram Moolenaar75537a92016-09-05 22:45:28 +0200359 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
360 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100361 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200362 if (this_due <= 1)
363 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200364 /* Save and restore a lot of flags, because the timer fires while
365 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200366 int save_timer_busy = timer_busy;
367 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200368 int save_did_emsg = did_emsg;
369 int save_called_emsg = called_emsg;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200370 int save_must_redraw = must_redraw;
Bram Moolenaare723c422017-09-06 23:40:10 +0200371 int save_trylevel = trylevel;
372 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200373 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare723c422017-09-06 23:40:10 +0200374 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200375 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200376
Bram Moolenaare723c422017-09-06 23:40:10 +0200377 /* Create a scope for running the timer callback, ignoring most of
378 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200379 timer_busy = timer_busy > 0 || vgetc_busy > 0;
380 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +0200381 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200382 did_emsg = FALSE;
383 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200384 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +0200385 trylevel = 0;
386 did_throw = FALSE;
387 current_exception = NULL;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200388 save_vimvars(&vvsave);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200389 timer->tr_firing = TRUE;
390 timer_callback(timer);
391 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200392
Bram Moolenaar75537a92016-09-05 22:45:28 +0200393 timer_next = timer->tr_next;
394 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200395 timer_busy = save_timer_busy;
396 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200397 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200398 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200399 did_emsg = save_did_emsg;
400 called_emsg = save_called_emsg;
401 trylevel = save_trylevel;
402 did_throw = save_did_throw;
403 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200404 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200405 if (must_redraw != 0)
406 need_update_screen = TRUE;
407 must_redraw = must_redraw > save_must_redraw
408 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200409 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200410
411 /* Only fire the timer again if it repeats and stop_timer() wasn't
412 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200413 if (timer->tr_repeat != 0 && timer->tr_id != -1
414 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200415 {
416 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100417 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200418 if (this_due < 1)
419 this_due = 1;
420 if (timer->tr_repeat > 0)
421 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100422 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200423 else
424 {
425 this_due = -1;
426 remove_timer(timer);
427 free_timer(timer);
428 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100429 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200430 if (this_due > 0 && (next_due == -1 || next_due > this_due))
431 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100432 }
433
434 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200435 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100436
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100437#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100438 if (bevalexpr_due_set)
439 {
440 this_due = proftime_time_left(&bevalexpr_due, &now);
441 if (this_due <= 1)
442 {
443 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100444 if (balloonEval == NULL)
445 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200446 balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100447 balloonEvalForTerm = TRUE;
448 }
449 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200450 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100451 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200452 setcursor();
453 out_flush();
454 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100455 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200456 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100457 next_due = this_due;
458 }
459#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200460#ifdef FEAT_TERMINAL
461 /* Some terminal windows may need their buffer updated. */
462 next_due = term_check_timers(next_due, &now);
463#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100464
Bram Moolenaar75537a92016-09-05 22:45:28 +0200465 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100466}
467
468/*
469 * Find a timer by ID. Returns NULL if not found;
470 */
471 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200472find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100473{
474 timer_T *timer;
475
Bram Moolenaar75537a92016-09-05 22:45:28 +0200476 if (id >= 0)
477 {
478 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
479 if (timer->tr_id == id)
480 return timer;
481 }
482 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100483}
484
485
486/*
487 * Stop a timer and delete it.
488 */
489 void
490stop_timer(timer_T *timer)
491{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200492 if (timer->tr_firing)
493 /* Free the timer after the callback returns. */
494 timer->tr_id = -1;
495 else
496 {
497 remove_timer(timer);
498 free_timer(timer);
499 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100500}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200501
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200502 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200503stop_all_timers(void)
504{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200505 timer_T *timer;
506 timer_T *timer_next;
507
508 for (timer = first_timer; timer != NULL; timer = timer_next)
509 {
510 timer_next = timer->tr_next;
511 stop_timer(timer);
512 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200513}
514
515 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200516add_timer_info(typval_T *rettv, timer_T *timer)
517{
518 list_T *list = rettv->vval.v_list;
519 dict_T *dict = dict_alloc();
520 dictitem_T *di;
521 long remaining;
522 proftime_T now;
523
524 if (dict == NULL)
525 return;
526 list_append_dict(list, dict);
527
Bram Moolenaare0be1672018-07-08 16:50:37 +0200528 dict_add_number(dict, "id", timer->tr_id);
529 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200530
531 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100532 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200533 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200534
Bram Moolenaare0be1672018-07-08 16:50:37 +0200535 dict_add_number(dict, "repeat",
536 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
537 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200538
539 di = dictitem_alloc((char_u *)"callback");
540 if (di != NULL)
541 {
542 if (dict_add(dict, di) == FAIL)
543 vim_free(di);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200544 else
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200545 put_callback(&timer->tr_callback, &di->di_tv);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200546 }
547}
548
549 void
550add_timer_info_all(typval_T *rettv)
551{
552 timer_T *timer;
553
554 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200555 if (timer->tr_id != -1)
556 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200557}
558
Bram Moolenaare3188e22016-05-31 21:13:04 +0200559/*
560 * Mark references in partials of timers.
561 */
562 int
563set_ref_in_timer(int copyID)
564{
565 int abort = FALSE;
566 timer_T *timer;
567 typval_T tv;
568
Bram Moolenaar75a1a942019-06-20 03:45:36 +0200569 for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
Bram Moolenaare3188e22016-05-31 21:13:04 +0200570 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200571 if (timer->tr_callback.cb_partial != NULL)
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200572 {
573 tv.v_type = VAR_PARTIAL;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200574 tv.vval.v_partial = timer->tr_callback.cb_partial;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200575 }
576 else
577 {
578 tv.v_type = VAR_FUNC;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200579 tv.vval.v_string = timer->tr_callback.cb_name;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200580 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200581 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
582 }
583 return abort;
584}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200585
586# if defined(EXITFREE) || defined(PROTO)
587 void
588timer_free_all()
589{
590 timer_T *timer;
591
592 while (first_timer != NULL)
593 {
594 timer = first_timer;
595 remove_timer(timer);
596 free_timer(timer);
597 }
598}
599# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100600# endif
601
Bram Moolenaar113e1072019-01-20 15:30:40 +0100602#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) && defined(FEAT_PROFILE)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200603# if defined(HAVE_MATH_H)
604# include <math.h>
605# endif
606
607/*
608 * Divide the time "tm" by "count" and store in "tm2".
609 */
610 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100611profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200612{
613 if (count == 0)
614 profile_zero(tm2);
615 else
616 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100617# ifdef MSWIN
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200618 tm2->QuadPart = tm->QuadPart / count;
619# else
620 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
621
622 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200623 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200624# endif
625 }
626}
627#endif
628
Bram Moolenaar76929292008-01-06 19:07:36 +0000629# if defined(FEAT_PROFILE) || defined(PROTO)
630/*
631 * Functions for profiling.
632 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100633static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +0000634static proftime_T prof_wait_time;
635
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000636/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000637 * Add the time "tm2" to "tm".
638 */
639 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100640profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000641{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100642# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000643 tm->QuadPart += tm2->QuadPart;
644# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000645 tm->tv_usec += tm2->tv_usec;
646 tm->tv_sec += tm2->tv_sec;
647 if (tm->tv_usec >= 1000000)
648 {
649 tm->tv_usec -= 1000000;
650 ++tm->tv_sec;
651 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000652# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000653}
654
655/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000656 * Add the "self" time from the total time and the children's time.
657 */
658 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100659profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +0000660{
661 /* Check that the result won't be negative. Can happen with recursive
662 * calls. */
Bram Moolenaar4f974752019-02-17 17:44:42 +0100663#ifdef MSWIN
Bram Moolenaar1056d982006-03-09 22:37:52 +0000664 if (total->QuadPart <= children->QuadPart)
665 return;
666#else
667 if (total->tv_sec < children->tv_sec
668 || (total->tv_sec == children->tv_sec
669 && total->tv_usec <= children->tv_usec))
670 return;
671#endif
672 profile_add(self, total);
673 profile_sub(self, children);
674}
675
676/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000677 * Get the current waittime.
678 */
679 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100680profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000681{
682 *tm = prof_wait_time;
683}
684
685/*
686 * Subtract the passed waittime since "tm" from "tma".
687 */
688 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100689profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000690{
691 proftime_T tm3 = prof_wait_time;
692
693 profile_sub(&tm3, tm);
694 profile_sub(tma, &tm3);
695}
696
697/*
698 * Return TRUE if "tm1" and "tm2" are equal.
699 */
700 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100701profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000702{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100703# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000704 return (tm1->QuadPart == tm2->QuadPart);
705# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000706 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000707# endif
708}
709
710/*
711 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
712 */
713 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100714profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000715{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100716# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000717 return (int)(tm2->QuadPart - tm1->QuadPart);
718# else
719 if (tm1->tv_sec == tm2->tv_sec)
720 return tm2->tv_usec - tm1->tv_usec;
721 return tm2->tv_sec - tm1->tv_sec;
722# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000723}
724
Bram Moolenaar05159a02005-02-26 23:04:13 +0000725static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000726static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000727
728/*
729 * ":profile cmd args"
730 */
731 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100732ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000733{
734 char_u *e;
735 int len;
736
737 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000738 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000739 e = skipwhite(e);
740
741 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
742 {
743 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +0200744 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000745 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000746 profile_zero(&prof_wait_time);
747 set_vim_var_nr(VV_PROFILING, 1L);
748 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000749 else if (do_profiling == PROF_NONE)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100750 emsg(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000751 else if (STRCMP(eap->arg, "pause") == 0)
752 {
753 if (do_profiling == PROF_YES)
754 profile_start(&pause_time);
755 do_profiling = PROF_PAUSED;
756 }
757 else if (STRCMP(eap->arg, "continue") == 0)
758 {
759 if (do_profiling == PROF_PAUSED)
760 {
761 profile_end(&pause_time);
762 profile_add(&prof_wait_time, &pause_time);
763 }
764 do_profiling = PROF_YES;
765 }
Bram Moolenaar05159a02005-02-26 23:04:13 +0000766 else
767 {
768 /* The rest is similar to ":breakadd". */
769 ex_breakadd(eap);
770 }
771}
772
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100773/* Command line expansion for :profile. */
774static enum
775{
776 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +0100777 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100778} pexpand_what;
779
780static char *pexpand_cmds[] = {
781 "start",
782#define PROFCMD_START 0
783 "pause",
784#define PROFCMD_PAUSE 1
785 "continue",
786#define PROFCMD_CONTINUE 2
787 "func",
788#define PROFCMD_FUNC 3
789 "file",
790#define PROFCMD_FILE 4
791 NULL
792#define PROFCMD_LAST 5
793};
794
795/*
796 * Function given to ExpandGeneric() to obtain the profile command
797 * specific expansion.
798 */
799 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100800get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100801{
802 switch (pexpand_what)
803 {
804 case PEXP_SUBCMD:
805 return (char_u *)pexpand_cmds[idx];
806 /* case PEXP_FUNC: TODO */
807 default:
808 return NULL;
809 }
810}
811
812/*
813 * Handle command line completion for :profile command.
814 */
815 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100816set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100817{
818 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100819
820 /* Default: expand subcommands. */
821 xp->xp_context = EXPAND_PROFILE;
822 pexpand_what = PEXP_SUBCMD;
823 xp->xp_pattern = arg;
824
825 end_subcmd = skiptowhite(arg);
826 if (*end_subcmd == NUL)
827 return;
828
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +0100829 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100830 {
831 xp->xp_context = EXPAND_FILES;
832 xp->xp_pattern = skipwhite(end_subcmd);
833 return;
834 }
835
836 /* TODO: expand function names after "func" */
837 xp->xp_context = EXPAND_NOTHING;
838}
839
Bram Moolenaar05159a02005-02-26 23:04:13 +0000840/*
841 * Dump the profiling info.
842 */
843 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100844profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 FILE *fd;
847
848 if (profile_fname != NULL)
849 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000850 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000851 if (fd == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100852 semsg(_(e_notopen), profile_fname);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000853 else
854 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000855 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000856 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000857 fclose(fd);
858 }
859 }
860}
861
862/*
863 * Start profiling script "fp".
864 */
865 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100866script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000867{
868 si->sn_pr_count = 0;
869 profile_zero(&si->sn_pr_total);
870 profile_zero(&si->sn_pr_self);
871
872 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
873 si->sn_prl_idx = -1;
874 si->sn_prof_on = TRUE;
875 si->sn_pr_nest = 0;
876}
877
878/*
Bram Moolenaar67435d92017-10-19 21:04:37 +0200879 * Save time when starting to invoke another script or function.
Bram Moolenaar05159a02005-02-26 23:04:13 +0000880 */
881 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100882script_prof_save(
883 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000884{
885 scriptitem_T *si;
886
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200887 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000888 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200889 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000890 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
891 profile_start(&si->sn_pr_child);
892 }
893 profile_get_wait(tm);
894}
895
896/*
897 * Count time spent in children after invoking another script or function.
898 */
899 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100900script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000901{
902 scriptitem_T *si;
903
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200904 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000905 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200906 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000907 if (si->sn_prof_on && --si->sn_pr_nest == 0)
908 {
909 profile_end(&si->sn_pr_child);
910 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
911 profile_add(&si->sn_pr_children, &si->sn_pr_child);
912 profile_add(&si->sn_prl_children, &si->sn_pr_child);
913 }
914 }
915}
916
917static proftime_T inchar_time;
918
919/*
920 * Called when starting to wait for the user to type a character.
921 */
922 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100923prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000924{
925 profile_start(&inchar_time);
926}
927
928/*
929 * Called when finished waiting for the user to type a character.
930 */
931 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100932prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000933{
934 profile_end(&inchar_time);
935 profile_add(&prof_wait_time, &inchar_time);
936}
937
938/*
939 * Dump the profiling results for all scripts in file "fd".
940 */
941 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100942script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943{
944 int id;
945 scriptitem_T *si;
946 int i;
947 FILE *sfd;
948 sn_prl_T *pp;
949
950 for (id = 1; id <= script_items.ga_len; ++id)
951 {
952 si = &SCRIPT_ITEM(id);
953 if (si->sn_prof_on)
954 {
955 fprintf(fd, "SCRIPT %s\n", si->sn_name);
956 if (si->sn_pr_count == 1)
957 fprintf(fd, "Sourced 1 time\n");
958 else
959 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
960 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
961 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
962 fprintf(fd, "\n");
963 fprintf(fd, "count total (s) self (s)\n");
964
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000965 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000966 if (sfd == NULL)
967 fprintf(fd, "Cannot open file!\n");
968 else
969 {
Bram Moolenaar67435d92017-10-19 21:04:37 +0200970 /* Keep going till the end of file, so that trailing
971 * continuation lines are listed. */
972 for (i = 0; ; ++i)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000973 {
974 if (vim_fgets(IObuff, IOSIZE, sfd))
975 break;
Bram Moolenaarac112f02017-12-05 16:46:28 +0100976 /* When a line has been truncated, append NL, taking care
977 * of multi-byte characters . */
978 if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
979 {
980 int n = IOSIZE - 2;
Bram Moolenaar13505972019-01-24 15:04:48 +0100981
Bram Moolenaarac112f02017-12-05 16:46:28 +0100982 if (enc_utf8)
983 {
984 /* Move to the first byte of this char.
985 * utf_head_off() doesn't work, because it checks
986 * for a truncated character. */
987 while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
988 --n;
989 }
990 else if (has_mbyte)
991 n -= mb_head_off(IObuff, IObuff + n);
Bram Moolenaarac112f02017-12-05 16:46:28 +0100992 IObuff[n] = NL;
993 IObuff[n + 1] = NUL;
994 }
Bram Moolenaar67435d92017-10-19 21:04:37 +0200995 if (i < si->sn_prl_ga.ga_len
996 && (pp = &PRL_ITEM(si, i))->snp_count > 0)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000997 {
998 fprintf(fd, "%5d ", pp->snp_count);
999 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1000 fprintf(fd, " ");
1001 else
1002 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1003 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1004 }
1005 else
1006 fprintf(fd, " ");
1007 fprintf(fd, "%s", IObuff);
1008 }
1009 fclose(sfd);
1010 }
1011 fprintf(fd, "\n");
1012 }
1013 }
1014}
1015
1016/*
1017 * Return TRUE when a function defined in the current script should be
1018 * profiled.
1019 */
1020 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001021prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001022{
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001023 if (current_sctx.sc_sid > 0)
1024 return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001025 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001026}
1027
1028# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029#endif
1030
1031/*
1032 * If 'autowrite' option set, try to write the file.
1033 * Careful: autocommands may make "buf" invalid!
1034 *
1035 * return FAIL for failure, OK otherwise
1036 */
1037 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001038autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001040 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001041 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001042
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 if (!(p_aw || p_awa) || !p_write
1044#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001045 /* never autowrite a "nofile" or "nowrite" buffer */
1046 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001048 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001050 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001051 r = buf_write_all(buf, forceit);
1052
1053 /* Writing may succeed but the buffer still changed, e.g., when there is a
1054 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001055 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001056 r = FAIL;
1057 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058}
1059
1060/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001061 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 */
1063 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001064autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065{
1066 buf_T *buf;
1067
1068 if (!(p_aw || p_awa) || !p_write)
1069 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001070 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001071 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001072 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001073 bufref_T bufref;
1074
1075 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001076
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001078
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001080 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 }
1083}
1084
1085/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001086 * Return TRUE if buffer was changed and cannot be abandoned.
1087 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001090check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001092 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001093 bufref_T bufref;
1094
1095 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001096
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 if ( !forceit
1098 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001099 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1100 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 {
1102#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1103 if ((p_confirm || cmdmod.confirm) && p_write)
1104 {
1105 buf_T *buf2;
1106 int count = 0;
1107
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001108 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001109 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 if (bufIsChanged(buf2)
1111 && (buf2->b_ffname != NULL
1112# ifdef FEAT_BROWSE
1113 || cmdmod.browse
1114# endif
1115 ))
1116 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001117 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 /* Autocommand deleted buffer, oops! It's not changed now. */
1119 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001120
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001122
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001123 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 /* Autocommand deleted buffer, oops! It's not changed now. */
1125 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 return bufIsChanged(buf);
1127 }
1128#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001129 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +02001130 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001131 else
Bram Moolenaar7a760922018-02-19 23:10:02 +01001132 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 return TRUE;
1134 }
1135 return FALSE;
1136}
1137
1138#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1139
1140#if defined(FEAT_BROWSE) || defined(PROTO)
1141/*
1142 * When wanting to write a file without a file name, ask the user for a name.
1143 */
1144 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001145browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146{
1147 if (buf->b_fname == NULL)
1148 {
1149 char_u *fname;
1150
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001151 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1152 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 if (fname != NULL)
1154 {
1155 if (setfname(buf, fname, NULL, TRUE) == OK)
1156 buf->b_flags |= BF_NOTEDITED;
1157 vim_free(fname);
1158 }
1159 }
1160}
1161#endif
1162
1163/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001164 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 * Must check 'write' option first!
1166 */
1167 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001168dialog_changed(
1169 buf_T *buf,
1170 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001172 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173 int ret;
1174 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001175 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +02001177 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 if (checkall)
1179 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1180 else
1181 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1182
Bram Moolenaar4ca41532019-05-09 21:48:37 +02001183 // Init ea pseudo-structure, this is needed for the check_overwrite()
1184 // function.
1185 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +02001186
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187 if (ret == VIM_YES)
1188 {
1189#ifdef FEAT_BROWSE
1190 /* May get file name, when there is none */
1191 browse_save_fname(buf);
1192#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001193 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1194 buf->b_fname, buf->b_ffname, FALSE) == OK)
1195 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 (void)buf_write_all(buf, FALSE);
1197 }
1198 else if (ret == VIM_NO)
1199 {
Bram Moolenaarc024b462019-06-08 18:07:21 +02001200 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201 }
1202 else if (ret == VIM_ALL)
1203 {
1204 /*
1205 * Write all modified files that can be written.
1206 * Skip readonly buffers, these need to be confirmed
1207 * individually.
1208 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001209 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210 {
1211 if (bufIsChanged(buf2)
1212 && (buf2->b_ffname != NULL
1213#ifdef FEAT_BROWSE
1214 || cmdmod.browse
1215#endif
1216 )
1217 && !buf2->b_p_ro)
1218 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001219 bufref_T bufref;
1220
1221 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222#ifdef FEAT_BROWSE
1223 /* May get file name, when there is none */
1224 browse_save_fname(buf2);
1225#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001226 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1227 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1228 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001230
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001232 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234 }
1235 }
1236 }
1237 else if (ret == VIM_DISCARDALL)
1238 {
1239 /*
1240 * mark all buffers as unchanged
1241 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001242 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +02001243 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 }
1245}
1246#endif
1247
1248/*
1249 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1250 * hidden, autowriting it or unloading it.
1251 */
1252 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001253can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254{
Bram Moolenaareb44a682017-08-03 22:44:55 +02001255 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 || !bufIsChanged(buf)
1257 || buf->b_nwindows > 1
1258 || autowrite(buf, forceit) == OK
1259 || forceit);
1260}
1261
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001262/*
1263 * Add a buffer number to "bufnrs", unless it's already there.
1264 */
1265 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001266add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001267{
1268 int i;
1269
1270 for (i = 0; i < *bufnump; ++i)
1271 if (bufnrs[i] == nr)
1272 return;
1273 bufnrs[*bufnump] = nr;
1274 *bufnump = *bufnump + 1;
1275}
1276
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277/*
1278 * Return TRUE if any buffer was changed and cannot be abandoned.
1279 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001280 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +01001281 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282 */
1283 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001284check_changed_any(
1285 int hidden, /* Only check hidden buffers */
1286 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001288 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289 buf_T *buf;
1290 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001291 int i;
1292 int bufnum = 0;
1293 int bufcount = 0;
1294 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001295 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001298 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001299 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001300 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001302 if (bufcount == 0)
1303 return FALSE;
1304
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001305 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001306 if (bufnrs == NULL)
1307 return FALSE;
1308
1309 /* curbuf */
1310 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001311
1312 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001313 FOR_ALL_WINDOWS(wp)
1314 if (wp->w_buffer != curbuf)
1315 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1316
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001317 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +02001318 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001319 if (tp != curtab)
1320 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1321 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001322
1323 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +02001324 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001325 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1326
1327 for (i = 0; i < bufnum; ++i)
1328 {
1329 buf = buflist_findnr(bufnrs[i]);
1330 if (buf == NULL)
1331 continue;
1332 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1333 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001334 bufref_T bufref;
1335
1336 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001337#ifdef FEAT_TERMINAL
1338 if (term_job_running(buf->b_term))
1339 {
1340 if (term_try_stop_job(buf) == FAIL)
1341 break;
1342 }
1343 else
1344#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001345 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02001346 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001347 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1348 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001349 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001350 break; /* didn't save - still changes */
1351 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352 }
1353
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001354 if (i >= bufnum)
1355 goto theend;
1356
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001357 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001358 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 exiting = FALSE;
1360#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1361 /*
1362 * When ":confirm" used, don't give an error message.
1363 */
1364 if (!(p_confirm || cmdmod.confirm))
1365#endif
1366 {
1367 /* There must be a wait_return for this message, do_buffer()
1368 * may cause a redraw. But wait_return() is a no-op when vgetc()
1369 * is busy (Quit used from window menu), then make sure we don't
1370 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001371 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372 {
1373 msg_row = cmdline_row;
1374 msg_col = 0;
1375 msg_didout = FALSE;
1376 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001377 if (
1378#ifdef FEAT_TERMINAL
1379 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001380 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +02001381 buf->b_fname)
1382 :
1383#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001384 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001385 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001386 {
1387 save = no_wait_return;
1388 no_wait_return = FALSE;
1389 wait_return(FALSE);
1390 no_wait_return = save;
1391 }
1392 }
1393
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394 /* Try to find a window that contains the buffer. */
1395 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001396 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397 if (wp->w_buffer == buf)
1398 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001399 bufref_T bufref;
1400
1401 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001402
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001403 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001404
Bram Moolenaarbdace832019-03-02 10:13:42 +01001405 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001406 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001407 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001408 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001409 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001410buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411
1412 /* Open the changed buffer in the current window. */
1413 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001414 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001415
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001416theend:
1417 vim_free(bufnrs);
1418 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419}
1420
1421/*
1422 * return FAIL if there is no file name, OK if there is one
1423 * give error message for FAIL
1424 */
1425 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001426check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427{
1428 if (curbuf->b_ffname == NULL)
1429 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001430 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431 return FAIL;
1432 }
1433 return OK;
1434}
1435
1436/*
1437 * flush the contents of a buffer, unless it has no file name
1438 *
1439 * return FAIL for failure, OK otherwise
1440 */
1441 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001442buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443{
1444 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001445 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446
1447 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1448 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1449 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001451 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01001452 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01001453 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455 return retval;
1456}
1457
1458/*
1459 * Code to handle the argument list.
1460 */
1461
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001462static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001463static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001464static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001465#define AL_SET 1
1466#define AL_ADD 2
1467#define AL_DEL 3
1468
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001470 * Isolate one argument, taking backticks.
1471 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001472 * Return a pointer to the start of the next argument.
1473 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001474 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001475do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476{
1477 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478 int inbacktick;
1479
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480 inbacktick = FALSE;
1481 for (p = str; *str; ++str)
1482 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001483 /* When the backslash is used for escaping the special meaning of a
1484 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485 if (rem_backslash(str))
1486 {
1487 *p++ = *str++;
1488 *p++ = *str;
1489 }
1490 else
1491 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001492 /* An item ends at a space not in backticks */
1493 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001495 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001496 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001497 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498 }
1499 }
1500 str = skipwhite(str);
1501 *p = NUL;
1502
1503 return str;
1504}
1505
Bram Moolenaar86b68352004-12-27 21:59:20 +00001506/*
1507 * Separate the arguments in "str" and return a list of pointers in the
1508 * growarray "gap".
1509 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001510 static int
1511get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001512{
1513 ga_init2(gap, (int)sizeof(char_u *), 20);
1514 while (*str != NUL)
1515 {
1516 if (ga_grow(gap, 1) == FAIL)
1517 {
1518 ga_clear(gap);
1519 return FAIL;
1520 }
1521 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1522
Bram Moolenaar398ee732017-08-03 14:29:14 +02001523 /* If str is escaped, don't handle backslashes or spaces */
1524 if (!escaped)
1525 return OK;
1526
Bram Moolenaar86b68352004-12-27 21:59:20 +00001527 /* Isolate one argument, change it in-place, put a NUL after it. */
1528 str = do_one_arg(str);
1529 }
1530 return OK;
1531}
1532
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001533#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001534/*
1535 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001536 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001537 * Return FAIL or OK.
1538 */
1539 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001540get_arglist_exp(
1541 char_u *str,
1542 int *fcountp,
1543 char_u ***fnamesp,
1544 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001545{
1546 garray_T ga;
1547 int i;
1548
Bram Moolenaar398ee732017-08-03 14:29:14 +02001549 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001550 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001551 if (wig == TRUE)
1552 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1553 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1554 else
1555 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1556 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1557
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001558 ga_clear(&ga);
1559 return i;
1560}
1561#endif
1562
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563/*
1564 * Redefine the argument list.
1565 */
1566 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001567set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568{
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001569 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571
1572/*
1573 * "what" == AL_SET: Redefine the argument list to 'str'.
1574 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1575 * "what" == AL_DEL: remove files in 'str' from the argument list.
1576 *
1577 * Return FAIL for failure, OK otherwise.
1578 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001580do_arglist(
1581 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01001582 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001583 int after UNUSED, // 0 means before first one
1584 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001585{
1586 garray_T new_ga;
1587 int exp_count;
1588 char_u **exp_files;
1589 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590 char_u *p;
1591 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001592 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593
1594 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001595 * Set default argument for ":argadd" command.
1596 */
1597 if (what == AL_ADD && *str == NUL)
1598 {
1599 if (curbuf->b_ffname == NULL)
1600 return FAIL;
1601 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001602 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001603 }
1604
1605 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 * Collect all file name arguments in "new_ga".
1607 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001608 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001609 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611 if (what == AL_DEL)
1612 {
1613 regmatch_T regmatch;
1614 int didone;
1615
1616 /*
1617 * Delete the items: use each item as a regexp and find a match in the
1618 * argument list.
1619 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001620 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1622 {
1623 p = ((char_u **)new_ga.ga_data)[i];
1624 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1625 if (p == NULL)
1626 break;
1627 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1628 if (regmatch.regprog == NULL)
1629 {
1630 vim_free(p);
1631 break;
1632 }
1633
1634 didone = FALSE;
1635 for (match = 0; match < ARGCOUNT; ++match)
1636 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1637 (colnr_T)0))
1638 {
1639 didone = TRUE;
1640 vim_free(ARGLIST[match].ae_fname);
1641 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1642 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1643 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001644 if (curwin->w_arg_idx > match)
1645 --curwin->w_arg_idx;
1646 --match;
1647 }
1648
Bram Moolenaar473de612013-06-08 18:19:48 +02001649 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650 vim_free(p);
1651 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001652 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653 }
1654 ga_clear(&new_ga);
1655 }
1656 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657 {
1658 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1659 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1660 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01001661 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001663 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664 return FAIL;
1665 }
1666
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 if (what == AL_ADD)
1668 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001669 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670 vim_free(exp_files);
1671 }
1672 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001673 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 }
1675
1676 alist_check_arg_idx();
1677
1678 return OK;
1679}
1680
1681/*
1682 * Check the validity of the arg_idx for each other window.
1683 */
1684 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001685alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001688 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689
Bram Moolenaarf740b292006-02-16 22:11:02 +00001690 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 if (win->w_alist == curwin->w_alist)
1692 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693}
1694
1695/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001696 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001697 * index.
1698 */
1699 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001700editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001701{
1702 return !(win->w_arg_idx >= WARGCOUNT(win)
1703 || (win->w_buffer->b_fnum
1704 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1705 && (win->w_buffer->b_ffname == NULL
1706 || !(fullpathcmp(
1707 alist_name(&WARGLIST(win)[win->w_arg_idx]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001708 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))));
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001709}
1710
1711/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712 * Check if window "win" is editing the w_arg_idx file in its argument list.
1713 */
1714 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001715check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001717 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001718 {
1719 /* We are not editing the current entry in the argument list.
1720 * Set "arg_had_last" if we are editing the last one. */
1721 win->w_arg_idx_invalid = TRUE;
1722 if (win->w_arg_idx != WARGCOUNT(win) - 1
1723 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 && GARGCOUNT > 0
1726 && win->w_arg_idx < GARGCOUNT
1727 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1728 || (win->w_buffer->b_ffname != NULL
1729 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001730 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731 arg_had_last = TRUE;
1732 }
1733 else
1734 {
1735 /* We are editing the current entry in the argument list.
1736 * Set "arg_had_last" if it's also the last one */
1737 win->w_arg_idx_invalid = FALSE;
1738 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02001739 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 arg_had_last = TRUE;
1741 }
1742}
1743
1744/*
1745 * ":args", ":argslocal" and ":argsglobal".
1746 */
1747 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001748ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749{
1750 int i;
1751
1752 if (eap->cmdidx != CMD_args)
1753 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754 alist_unlink(ALIST(curwin));
1755 if (eap->cmdidx == CMD_argglobal)
1756 ALIST(curwin) = &global_alist;
1757 else /* eap->cmdidx == CMD_arglocal */
1758 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 }
1760
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01001761 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 {
1763 /*
1764 * ":args file ..": define new argument list, handle like ":next"
1765 * Also for ":argslocal file .." and ":argsglobal file ..".
1766 */
1767 ex_next(eap);
1768 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001769 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 {
1771 /*
1772 * ":args": list arguments.
1773 */
1774 if (ARGCOUNT > 0)
1775 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001776 char_u **items = ALLOC_MULT(char_u *, ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001777
1778 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001780 /* Overwrite the command, for a short list there is no
1781 * scrolling required and no wait_return(). */
1782 gotocmdline(TRUE);
1783
1784 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001785 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001786 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
1787 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 }
1789 }
1790 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 else if (eap->cmdidx == CMD_arglocal)
1792 {
1793 garray_T *gap = &curwin->w_alist->al_ga;
1794
1795 /*
1796 * ":argslocal": make a local copy of the global argument list.
1797 */
1798 if (ga_grow(gap, GARGCOUNT) == OK)
1799 for (i = 0; i < GARGCOUNT; ++i)
1800 if (GARGLIST[i].ae_fname != NULL)
1801 {
1802 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1803 vim_strsave(GARGLIST[i].ae_fname);
1804 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1805 GARGLIST[i].ae_fnum;
1806 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807 }
1808 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809}
1810
1811/*
1812 * ":previous", ":sprevious", ":Next" and ":sNext".
1813 */
1814 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001815ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816{
1817 /* If past the last one already, go to the last one. */
1818 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1819 do_argfile(eap, ARGCOUNT - 1);
1820 else
1821 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1822}
1823
1824/*
1825 * ":rewind", ":first", ":sfirst" and ":srewind".
1826 */
1827 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001828ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829{
1830 do_argfile(eap, 0);
1831}
1832
1833/*
1834 * ":last" and ":slast".
1835 */
1836 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001837ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838{
1839 do_argfile(eap, ARGCOUNT - 1);
1840}
1841
1842/*
1843 * ":argument" and ":sargument".
1844 */
1845 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001846ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847{
1848 int i;
1849
1850 if (eap->addr_count > 0)
1851 i = eap->line2 - 1;
1852 else
1853 i = curwin->w_arg_idx;
1854 do_argfile(eap, i);
1855}
1856
1857/*
1858 * Edit file "argn" of the argument lists.
1859 */
1860 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001861do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862{
1863 int other;
1864 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001865 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866
Bram Moolenaar8cdbd5b2019-06-16 15:50:45 +02001867 if (ERROR_IF_POPUP_WINDOW)
Bram Moolenaar815b76b2019-06-01 14:15:52 +02001868 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 if (argn < 0 || argn >= ARGCOUNT)
1870 {
1871 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001872 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001874 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001876 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 }
1878 else
1879 {
1880 setpcmark();
1881#ifdef FEAT_GUI
1882 need_mouse_correct = TRUE;
1883#endif
1884
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00001885 /* split window or create new tab page first */
1886 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 {
1888 if (win_split(0, 0) == FAIL)
1889 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001890 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 }
1892 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 {
1894 /*
1895 * if 'hidden' set, only check for changed file when re-editing
1896 * the same buffer
1897 */
1898 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02001899 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 {
1901 p = fix_fname(alist_name(&ARGLIST[argn]));
1902 other = otherfile(p);
1903 vim_free(p);
1904 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001905 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001906 && check_changed(curbuf, CCGD_AW
1907 | (other ? 0 : CCGD_MULTWIN)
1908 | (eap->forceit ? CCGD_FORCEIT : 0)
1909 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 return;
1911 }
1912
1913 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001914 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 arg_had_last = TRUE;
1916
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001917 /* Edit the file; always use the last known line number.
1918 * When it fails (e.g. Abort for already edited file) restore the
1919 * argument index. */
1920 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02001922 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001923 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001924 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001926 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001927 setmark('\'');
1928 }
1929}
1930
1931/*
1932 * ":next", and commands that behave like it.
1933 */
1934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001935ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936{
1937 int i;
1938
1939 /*
1940 * check for changed buffer now, if this fails the argument list is not
1941 * redefined.
1942 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02001943 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001945 || !check_changed(curbuf, CCGD_AW
1946 | (eap->forceit ? CCGD_FORCEIT : 0)
1947 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 {
1949 if (*eap->arg != NUL) /* redefine file list */
1950 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001951 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 return;
1953 i = 0;
1954 }
1955 else
1956 i = curwin->w_arg_idx + (int)eap->line2;
1957 do_argfile(eap, i);
1958 }
1959}
1960
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961/*
1962 * ":argedit"
1963 */
1964 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001965ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966{
Bram Moolenaar90305c62017-07-16 15:31:17 +02001967 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001968 // Whether curbuf will be reused, curbuf->b_ffname will be set.
1969 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001971 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02001972 return;
1973#ifdef FEAT_TITLE
1974 maketitle();
1975#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001977 if (curwin->w_arg_idx == 0
1978 && (curbuf->b_ml.ml_flags & ML_EMPTY)
1979 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02001980 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001981 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02001982 if (i < ARGCOUNT)
1983 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984}
1985
1986/*
1987 * ":argadd"
1988 */
1989 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001990ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001991{
1992 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001993 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
1994 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995#ifdef FEAT_TITLE
1996 maketitle();
1997#endif
1998}
1999
2000/*
2001 * ":argdelete"
2002 */
2003 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002004ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005{
2006 int i;
2007 int n;
2008
2009 if (eap->addr_count > 0)
2010 {
2011 /* ":1,4argdel": Delete all arguments in the range. */
2012 if (eap->line2 > ARGCOUNT)
2013 eap->line2 = ARGCOUNT;
2014 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002015 if (*eap->arg != NUL)
2016 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002017 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002018 else if (n <= 0)
2019 {
2020 /* Don't give an error for ":%argdel" if the list is empty. */
2021 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002022 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002023 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024 else
2025 {
2026 for (i = eap->line1; i <= eap->line2; ++i)
2027 vim_free(ARGLIST[i - 1].ae_fname);
2028 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2029 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2030 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 if (curwin->w_arg_idx >= eap->line2)
2032 curwin->w_arg_idx -= n;
2033 else if (curwin->w_arg_idx > eap->line1)
2034 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002035 if (ARGCOUNT == 0)
2036 curwin->w_arg_idx = 0;
2037 else if (curwin->w_arg_idx >= ARGCOUNT)
2038 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 }
2040 }
2041 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002042 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002044 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002045#ifdef FEAT_TITLE
2046 maketitle();
2047#endif
2048}
2049
2050/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002051 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002052 */
2053 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002054ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055{
2056 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002057 win_T *wp;
2058 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01002059 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002061#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002064 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002065#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002066 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002067 int qf_idx;
2068#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002069
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002070#ifndef FEAT_QUICKFIX
2071 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2072 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2073 {
2074 ex_ni(eap);
2075 return;
2076 }
2077#endif
2078
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002079#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002080 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002081 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2082 * great speed improvement. */
2083 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002084#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002085#ifdef FEAT_CLIPBOARD
2086 start_global_changes();
2087#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088
2089 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002090 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02002091 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002092 || !check_changed(curbuf, CCGD_AW
2093 | (eap->forceit ? CCGD_FORCEIT : 0)
2094 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002095 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002097 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002098 wp = firstwin;
2099 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002100 switch (eap->cmdidx)
2101 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01002102 case CMD_windo:
2103 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2104 i++;
2105 break;
2106 case CMD_tabdo:
2107 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2108 i++;
2109 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002110 case CMD_argdo:
2111 i = eap->line1 - 1;
2112 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002113 default:
2114 break;
2115 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116 /* set pcmark now */
2117 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002118 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002119 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002120 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002121 || !buf->b_p_bl); buf = buf->b_next)
2122 if (buf->b_fnum > eap->line2)
2123 {
2124 buf = NULL;
2125 break;
2126 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002127 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002128 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002129 }
2130#ifdef FEAT_QUICKFIX
2131 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2132 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2133 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02002134 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002135 if (qf_size <= 0 || eap->line1 > qf_size)
2136 buf = NULL;
2137 else
2138 {
2139 ex_cc(eap);
2140
2141 buf = curbuf;
2142 i = eap->line1 - 1;
2143 if (eap->addr_count <= 0)
2144 /* default is all the quickfix/location list entries */
2145 eap->line2 = qf_size;
2146 }
2147 }
2148#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002149 else
2150 setpcmark();
2151 listcmd_busy = TRUE; /* avoids setting pcmark below */
2152
Bram Moolenaare25bb902015-02-27 20:33:37 +01002153 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154 {
2155 if (eap->cmdidx == CMD_argdo)
2156 {
2157 /* go to argument "i" */
2158 if (i == ARGCOUNT)
2159 break;
2160 /* Don't call do_argfile() when already there, it will try
2161 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002162 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002163 {
2164 /* Clear 'shm' to avoid that the file message overwrites
2165 * any output from the command. */
2166 p_shm_save = vim_strsave(p_shm);
2167 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002169 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2170 vim_free(p_shm_save);
2171 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 if (curwin->w_arg_idx != i)
2173 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002175 else if (eap->cmdidx == CMD_windo)
2176 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002177 /* go to window "wp" */
2178 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002179 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002180 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002181 if (curwin != wp)
2182 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002183 wp = curwin->w_next;
2184 }
2185 else if (eap->cmdidx == CMD_tabdo)
2186 {
2187 /* go to window "tp" */
2188 if (!valid_tabpage(tp))
2189 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002190 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002191 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002192 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 else if (eap->cmdidx == CMD_bufdo)
2194 {
2195 /* Remember the number of the next listed buffer, in case
2196 * ":bwipe" is used or autocommands do something strange. */
2197 next_fnum = -1;
2198 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2199 if (buf->b_p_bl)
2200 {
2201 next_fnum = buf->b_fnum;
2202 break;
2203 }
2204 }
2205
Bram Moolenaara162bc52015-01-07 16:54:21 +01002206 ++i;
2207
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208 /* execute the command */
2209 do_cmdline(eap->arg, eap->getline, eap->cookie,
2210 DOCMD_VERBOSE + DOCMD_NOWAIT);
2211
2212 if (eap->cmdidx == CMD_bufdo)
2213 {
2214 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002215 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002216 break;
2217 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02002218 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002219 if (buf->b_fnum == next_fnum)
2220 break;
2221 if (buf == NULL)
2222 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002223
2224 /* Go to the next buffer. Clear 'shm' to avoid that the file
2225 * message overwrites any output from the command. */
2226 p_shm_save = vim_strsave(p_shm);
2227 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002229 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2230 vim_free(p_shm_save);
2231
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002232 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233 if (curbuf->b_fnum != next_fnum)
2234 break;
2235 }
2236
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002237#ifdef FEAT_QUICKFIX
2238 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2239 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2240 {
2241 if (i >= qf_size || i >= eap->line2)
2242 break;
2243
2244 qf_idx = qf_get_cur_idx(eap);
2245
2246 ex_cnext(eap);
2247
2248 /* If jumping to the next quickfix entry fails, quit here */
2249 if (qf_get_cur_idx(eap) == qf_idx)
2250 break;
2251 }
2252#endif
2253
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 if (eap->cmdidx == CMD_windo)
2255 {
2256 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01002257
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 /* required when 'scrollbind' has been set */
2259 if (curwin->w_p_scb)
2260 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002262
Bram Moolenaara162bc52015-01-07 16:54:21 +01002263 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2264 if (i+1 > eap->line2)
2265 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002266 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2267 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 }
2269 listcmd_busy = FALSE;
2270 }
2271
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002272#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002273 if (save_ei != NULL)
2274 {
2275 au_event_restore(save_ei);
2276 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2277 curbuf->b_fname, TRUE, curbuf);
2278 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002280#ifdef FEAT_CLIPBOARD
2281 end_global_changes();
2282#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283}
2284
2285/*
2286 * Add files[count] to the arglist of the current window after arg "after".
2287 * The file names in files[count] must have been allocated and are taken over.
2288 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002290 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002291alist_add_list(
2292 int count,
2293 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002294 int after, // where to add: 0 = before first one
2295 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296{
2297 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002298 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299
2300 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2301 {
2302 if (after < 0)
2303 after = 0;
2304 if (after > ARGCOUNT)
2305 after = ARGCOUNT;
2306 if (after < ARGCOUNT)
2307 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2308 (ARGCOUNT - after) * sizeof(aentry_T));
2309 for (i = 0; i < count; ++i)
2310 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002311 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
2312
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002314 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315 }
2316 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002317 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2318 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002319 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 }
2321
2322 for (i = 0; i < count; ++i)
2323 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324}
2325
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02002326#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2327/*
2328 * Function given to ExpandGeneric() to obtain the possible arguments of the
2329 * argedit and argdelete commands.
2330 */
2331 char_u *
2332get_arglist_name(expand_T *xp UNUSED, int idx)
2333{
2334 if (idx >= ARGCOUNT)
2335 return NULL;
2336
2337 return alist_name(&ARGLIST[idx]);
2338}
2339#endif
2340
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02002341
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342#ifdef FEAT_EVAL
2343/*
2344 * ":compiler[!] {name}"
2345 */
2346 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002347ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348{
2349 char_u *buf;
2350 char_u *old_cur_comp = NULL;
2351 char_u *p;
2352
2353 if (*eap->arg == NUL)
2354 {
2355 /* List all compiler scripts. */
2356 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2357 /* ) keep the indenter happy... */
2358 }
2359 else
2360 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02002361 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 if (buf != NULL)
2363 {
2364 if (eap->forceit)
2365 {
2366 /* ":compiler! {name}" sets global options */
2367 do_cmdline_cmd((char_u *)
2368 "command -nargs=* CompilerSet set <args>");
2369 }
2370 else
2371 {
2372 /* ":compiler! {name}" sets local options.
2373 * To remain backwards compatible "current_compiler" is always
2374 * used. A user's compiler plugin may set it, the distributed
2375 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002376 * "b:current_compiler" and restore "current_compiler".
2377 * Explicitly prepend "g:" to make it work in a function. */
2378 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 if (old_cur_comp != NULL)
2380 old_cur_comp = vim_strsave(old_cur_comp);
2381 do_cmdline_cmd((char_u *)
2382 "command -nargs=* CompilerSet setlocal <args>");
2383 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002384 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002385 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386
2387 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002388 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002389 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 vim_free(buf);
2391
2392 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2393
2394 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002395 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 if (p != NULL)
2397 set_internal_string_var((char_u *)"b:current_compiler", p);
2398
2399 /* Restore "current_compiler" for ":compiler {name}". */
2400 if (!eap->forceit)
2401 {
2402 if (old_cur_comp != NULL)
2403 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002404 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 old_cur_comp);
2406 vim_free(old_cur_comp);
2407 }
2408 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002409 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002410 }
2411 }
2412 }
2413}
2414#endif
2415
2416/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002417 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418 */
2419 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002420ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002422 char_u *arg = eap->arg;
2423 char_u *p = skiptowhite(arg);
2424 int len = (int)(p - arg);
2425 int flags = eap->forceit ? DIP_ALL : 0;
2426
2427 if (STRNCMP(arg, "START", len) == 0)
2428 {
2429 flags += DIP_START + DIP_NORTP;
2430 arg = skipwhite(arg + len);
2431 }
2432 else if (STRNCMP(arg, "OPT", len) == 0)
2433 {
2434 flags += DIP_OPT + DIP_NORTP;
2435 arg = skipwhite(arg + len);
2436 }
2437 else if (STRNCMP(arg, "PACK", len) == 0)
2438 {
2439 flags += DIP_START + DIP_OPT + DIP_NORTP;
2440 arg = skipwhite(arg + len);
2441 }
2442 else if (STRNCMP(arg, "ALL", len) == 0)
2443 {
2444 flags += DIP_START + DIP_OPT;
2445 arg = skipwhite(arg + len);
2446 }
2447
2448 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449}
2450
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002452source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002454 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455}
2456
2457/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002458 * Find the file "name" in all directories in "path" and invoke
2459 * "callback(fname, cookie)".
2460 * "name" can contain wildcards.
2461 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2462 * When "flags" has DIP_DIR: find directories instead of files.
2463 * When "flags" has DIP_ERR: give an error message if there is no match.
2464 *
2465 * return FAIL when no file could be sourced, OK otherwise.
2466 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01002467 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002468do_in_path(
2469 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002470 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01002471 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002472 void (*callback)(char_u *fname, void *ck),
2473 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474{
2475 char_u *rtp;
2476 char_u *np;
2477 char_u *buf;
2478 char_u *rtp_copy;
2479 char_u *tail;
2480 int num_files;
2481 char_u **files;
2482 int i;
2483 int did_one = FALSE;
2484#ifdef AMIGA
2485 struct Process *proc = (struct Process *)FindTask(0L);
2486 APTR save_winptr = proc->pr_WindowPtr;
2487
2488 /* Avoid a requester here for a volume that doesn't exist. */
2489 proc->pr_WindowPtr = (APTR)-1L;
2490#endif
2491
2492 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2493 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002494 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 buf = alloc(MAXPATHL);
2496 if (buf != NULL && rtp_copy != NULL)
2497 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002498 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002499 {
2500 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002501 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002502 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002503 verbose_leave();
2504 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002505
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506 /* Loop over all entries in 'runtimepath'. */
2507 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01002508 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02002510 size_t buflen;
2511
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512 /* Copy the path from 'runtimepath' to buf[]. */
2513 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02002514 buflen = STRLEN(buf);
2515
2516 /* Skip after or non-after directories. */
2517 if (flags & (DIP_NOAFTER | DIP_AFTER))
2518 {
2519 int is_after = buflen >= 5
2520 && STRCMP(buf + buflen - 5, "after") == 0;
2521
2522 if ((is_after && (flags & DIP_NOAFTER))
2523 || (!is_after && (flags & DIP_AFTER)))
2524 continue;
2525 }
2526
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002527 if (name == NULL)
2528 {
2529 (*callback)(buf, (void *) &cookie);
2530 if (!did_one)
2531 did_one = (cookie == NULL);
2532 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02002533 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534 {
2535 add_pathsep(buf);
2536 tail = buf + STRLEN(buf);
2537
2538 /* Loop over all patterns in "name" */
2539 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01002540 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 {
2542 /* Append the pattern from "name" to buf[]. */
2543 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2544 "\t ");
2545
2546 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002547 {
2548 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002549 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002550 verbose_leave();
2551 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552
2553 /* Expand wildcards, invoke the callback for each match. */
2554 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01002555 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 {
2557 for (i = 0; i < num_files; ++i)
2558 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002559 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01002561 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562 break;
2563 }
2564 FreeWild(num_files, files);
2565 }
2566 }
2567 }
2568 }
2569 }
2570 vim_free(buf);
2571 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002572 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002573 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002574 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
2575
2576 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002577 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002578 else if (p_verbose > 0)
2579 {
2580 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002581 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002582 verbose_leave();
2583 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002584 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585
2586#ifdef AMIGA
2587 proc->pr_WindowPtr = save_winptr;
2588#endif
2589
2590 return did_one ? OK : FAIL;
2591}
2592
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002593/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002594 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002595 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002596 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
2597 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002598 * Returns OK when at least one match found, FAIL otherwise.
2599 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002600 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002601 * passed by reference in this case, setting it to NULL indicates that callback
2602 * has done its job.
2603 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002604 static int
2605do_in_path_and_pp(
2606 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002607 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002608 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002609 void (*callback)(char_u *fname, void *ck),
2610 void *cookie)
2611{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002612 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002613 char_u *s;
2614 int len;
2615 char *start_dir = "pack/*/start/*/%s";
2616 char *opt_dir = "pack/*/opt/*/%s";
2617
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002618 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002619 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002620
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002621 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002622 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002623 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002624 s = alloc(len);
2625 if (s == NULL)
2626 return FAIL;
2627 vim_snprintf((char *)s, len, start_dir, name);
2628 done = do_in_path(p_pp, s, flags, callback, cookie);
2629 vim_free(s);
2630 }
2631
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002632 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002633 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002634 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002635 s = alloc(len);
2636 if (s == NULL)
2637 return FAIL;
2638 vim_snprintf((char *)s, len, opt_dir, name);
2639 done = do_in_path(p_pp, s, flags, callback, cookie);
2640 vim_free(s);
2641 }
2642
2643 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002644}
2645
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002646/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002647 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2648 */
2649 int
2650do_in_runtimepath(
2651 char_u *name,
2652 int flags,
2653 void (*callback)(char_u *fname, void *ck),
2654 void *cookie)
2655{
2656 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2657}
2658
2659/*
2660 * Source the file "name" from all directories in 'runtimepath'.
2661 * "name" can contain wildcards.
2662 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2663 *
2664 * return FAIL when no file could be sourced, OK otherwise.
2665 */
2666 int
2667source_runtime(char_u *name, int flags)
2668{
2669 return source_in_path(p_rtp, name, flags);
2670}
2671
2672/*
2673 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2674 */
2675 int
2676source_in_path(char_u *path, char_u *name, int flags)
2677{
2678 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2679}
2680
2681
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002682#if defined(FEAT_EVAL) || defined(PROTO)
2683
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002684/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002685 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002686 */
2687 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002688source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002689{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002690 int num_files;
2691 char_u **files;
2692 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002693
Bram Moolenaarf3654822016-03-04 22:12:23 +01002694 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002695 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002696 for (i = 0; i < num_files; ++i)
2697 (void)do_source(files[i], FALSE, DOSO_NONE);
2698 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002699 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002700}
2701
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002702/*
2703 * Add the package directory to 'runtimepath'.
2704 */
2705 static int
2706add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002707{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002708 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002709 char_u *entry;
2710 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002711 int c;
2712 char_u *new_rtp;
2713 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002714 size_t oldlen;
2715 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002716 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002717 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002718 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002719 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002720 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002721 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002722 char_u *buf = NULL;
2723 char_u *rtp_ffname;
2724 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002725 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002726
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002727 p4 = p3 = p2 = p1 = get_past_head(fname);
2728 for (p = p1; *p; MB_PTR_ADV(p))
2729 if (vim_ispathsep_nocolon(*p))
2730 {
2731 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2732 }
2733
2734 /* now we have:
2735 * rtp/pack/name/start/name
2736 * p4 p3 p2 p1
2737 *
2738 * find the part up to "pack" in 'runtimepath' */
2739 c = *++p4; /* append pathsep in order to expand symlink */
2740 *p4 = NUL;
2741 ffname = fix_fname(fname);
2742 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002743 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002744 return FAIL;
2745
Bram Moolenaar99396d42018-09-08 18:21:16 +02002746 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2747 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002748 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002749 buf = alloc(MAXPATHL);
2750 if (buf == NULL)
2751 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002752 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002753 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002754 char_u *cur_entry = entry;
2755
2756 copy_option_part(&entry, buf, MAXPATHL, ",");
2757 if (insp == NULL)
2758 {
2759 add_pathsep(buf);
2760 rtp_ffname = fix_fname(buf);
2761 if (rtp_ffname == NULL)
2762 goto theend;
2763 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2764 vim_free(rtp_ffname);
2765 if (match)
2766 // Insert "ffname" after this entry (and comma).
2767 insp = entry;
2768 }
2769
2770 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2771 && p > buf
2772 && vim_ispathsep(p[-1])
2773 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2774 {
2775 if (insp == NULL)
2776 // Did not find "ffname" before the first "after" directory,
2777 // insert it before this entry.
2778 insp = cur_entry;
2779 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002780 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002781 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002782 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002783
Bram Moolenaar99396d42018-09-08 18:21:16 +02002784 if (insp == NULL)
2785 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002786 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002787
Bram Moolenaar99396d42018-09-08 18:21:16 +02002788 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002789 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2790 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002791 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002792
2793 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002794 addlen = STRLEN(fname) + 1; // add one for comma
Bram Moolenaar51e14382019-05-25 20:21:28 +02002795 new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002796 if (new_rtp == NULL)
2797 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002798
2799 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2800 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002801 keep = (int)(insp - p_rtp);
2802 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002803 new_rtp_len = keep;
2804 if (*insp == NUL)
2805 new_rtp[new_rtp_len++] = ','; // add comma before
2806 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2807 new_rtp_len += addlen - 1;
2808 if (*insp != NUL)
2809 new_rtp[new_rtp_len++] = ','; // add comma after
2810
2811 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002812 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002813 int keep_after = (int)(after_insp - p_rtp);
2814
2815 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2816 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2817 keep_after - keep);
2818 new_rtp_len += keep_after - keep;
2819 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2820 new_rtp_len += afterlen - 1;
2821 new_rtp[new_rtp_len++] = ',';
2822 keep = keep_after;
2823 }
2824
2825 if (p_rtp[keep] != NUL)
2826 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2827 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2828 else
2829 new_rtp[new_rtp_len] = NUL;
2830
2831 if (afterlen > 0 && after_insp == NULL)
2832 {
2833 // Append afterdir when "after" was not found:
2834 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002835 STRCAT(new_rtp, ",");
2836 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002837 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002838
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002839 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2840 vim_free(new_rtp);
2841 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002842
2843theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002844 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002845 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002846 vim_free(afterdir);
2847 return retval;
2848}
2849
2850/*
2851 * Load scripts in "plugin" and "ftdetect" directories of the package.
2852 */
2853 static int
2854load_pack_plugin(char_u *fname)
2855{
2856 static char *plugpat = "%s/plugin/**/*.vim";
2857 static char *ftpat = "%s/ftdetect/*.vim";
2858 int len;
2859 char_u *ffname = fix_fname(fname);
2860 char_u *pat = NULL;
2861 int retval = FAIL;
2862
2863 if (ffname == NULL)
2864 return FAIL;
2865 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2866 pat = alloc(len);
2867 if (pat == NULL)
2868 goto theend;
2869 vim_snprintf((char *)pat, len, plugpat, ffname);
2870 source_all_matches(pat);
2871
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002872 {
2873 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2874
2875 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2876 * found when it loads. */
2877 if (cmd != NULL && eval_to_number(cmd) > 0)
2878 {
2879 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2880 vim_snprintf((char *)pat, len, ftpat, ffname);
2881 source_all_matches(pat);
2882 do_cmdline_cmd((char_u *)"augroup END");
2883 }
2884 vim_free(cmd);
2885 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002886 vim_free(pat);
2887 retval = OK;
2888
2889theend:
2890 vim_free(ffname);
2891 return retval;
2892}
2893
2894/* used for "cookie" of add_pack_plugin() */
2895static int APP_ADD_DIR;
2896static int APP_LOAD;
2897static int APP_BOTH;
2898
2899 static void
2900add_pack_plugin(char_u *fname, void *cookie)
2901{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002902 if (cookie != &APP_LOAD)
2903 {
2904 char_u *buf = alloc(MAXPATHL);
2905 char_u *p;
2906 int found = FALSE;
2907
2908 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002909 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002910 p = p_rtp;
2911 while (*p != NUL)
2912 {
2913 copy_option_part(&p, buf, MAXPATHL, ",");
2914 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2915 {
2916 found = TRUE;
2917 break;
2918 }
2919 }
2920 vim_free(buf);
2921 if (!found)
2922 /* directory is not yet in 'runtimepath', add it */
2923 if (add_pack_dir_to_rtp(fname) == FAIL)
2924 return;
2925 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002926
2927 if (cookie != &APP_ADD_DIR)
2928 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002929}
2930
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002931/*
2932 * Add all packages in the "start" directory to 'runtimepath'.
2933 */
2934 void
2935add_pack_start_dirs(void)
2936{
2937 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2938 add_pack_plugin, &APP_ADD_DIR);
2939}
2940
2941/*
2942 * Load plugins from all packages in the "start" directory.
2943 */
2944 void
2945load_start_packages(void)
2946{
2947 did_source_packages = TRUE;
2948 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2949 add_pack_plugin, &APP_LOAD);
2950}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002951
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002952/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002953 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002954 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002955 */
2956 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002957ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002958{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002959 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002960 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002961 /* First do a round to add all directories to 'runtimepath', then load
2962 * the plugins. This allows for plugins to use an autoload directory
2963 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002964 add_pack_start_dirs();
2965 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002966 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002967}
2968
2969/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002970 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002971 */
2972 void
2973ex_packadd(exarg_T *eap)
2974{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002975 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002976 int len;
2977 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002978 int round;
2979 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002980
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002981 /* Round 1: use "start", round 2: use "opt". */
2982 for (round = 1; round <= 2; ++round)
2983 {
2984 /* Only look under "start" when loading packages wasn't done yet. */
2985 if (round == 1 && did_source_packages)
2986 continue;
2987
2988 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002989 pat = alloc(len);
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002990 if (pat == NULL)
2991 return;
2992 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
2993 /* The first round don't give a "not found" error, in the second round
2994 * only when nothing was found in the first round. */
2995 res = do_in_path(p_pp, (char_u *)pat,
2996 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
2997 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
2998 vim_free(pat);
2999 }
Bram Moolenaar91715872016-03-03 17:13:03 +01003000}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003001#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01003002
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003003#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004/*
3005 * ":options"
3006 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003008ex_options(
3009 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010{
Bram Moolenaare0b59492019-05-21 20:54:45 +02003011 vim_setenv((char_u *)"OPTWIN_CMD",
3012 (char_u *)(cmdmod.tab ? "tab"
3013 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3015}
3016#endif
3017
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003018#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3019
3020# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3021/*
3022 * Detect Python 3 or 2, and initialize 'pyxversion'.
3023 */
3024 void
3025init_pyxversion(void)
3026{
3027 if (p_pyx == 0)
3028 {
3029 if (python3_enabled(FALSE))
3030 p_pyx = 3;
3031 else if (python_enabled(FALSE))
3032 p_pyx = 2;
3033 }
3034}
3035# endif
3036
3037/*
3038 * Does a file contain one of the following strings at the beginning of any
3039 * line?
3040 * "#!(any string)python2" => returns 2
3041 * "#!(any string)python3" => returns 3
3042 * "# requires python 2.x" => returns 2
3043 * "# requires python 3.x" => returns 3
3044 * otherwise return 0.
3045 */
3046 static int
3047requires_py_version(char_u *filename)
3048{
3049 FILE *file;
3050 int requires_py_version = 0;
3051 int i, lines;
3052
3053 lines = (int)p_mls;
3054 if (lines < 0)
3055 lines = 5;
3056
3057 file = mch_fopen((char *)filename, "r");
3058 if (file != NULL)
3059 {
3060 for (i = 0; i < lines; i++)
3061 {
3062 if (vim_fgets(IObuff, IOSIZE, file))
3063 break;
3064 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3065 {
3066 /* Check shebang. */
3067 if (strstr((char *)IObuff + 2, "python2") != NULL)
3068 {
3069 requires_py_version = 2;
3070 break;
3071 }
3072 if (strstr((char *)IObuff + 2, "python3") != NULL)
3073 {
3074 requires_py_version = 3;
3075 break;
3076 }
3077 }
3078 IObuff[21] = '\0';
3079 if (STRCMP("# requires python 2.x", IObuff) == 0)
3080 {
3081 requires_py_version = 2;
3082 break;
3083 }
3084 if (STRCMP("# requires python 3.x", IObuff) == 0)
3085 {
3086 requires_py_version = 3;
3087 break;
3088 }
3089 }
3090 fclose(file);
3091 }
3092 return requires_py_version;
3093}
3094
3095
3096/*
3097 * Source a python file using the requested python version.
3098 */
3099 static void
3100source_pyx_file(exarg_T *eap, char_u *fname)
3101{
3102 exarg_T ex;
3103 int v = requires_py_version(fname);
3104
3105# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3106 init_pyxversion();
3107# endif
3108 if (v == 0)
3109 {
3110# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3111 /* user didn't choose a preference, 'pyx' is used */
3112 v = p_pyx;
3113# elif defined(FEAT_PYTHON)
3114 v = 2;
3115# elif defined(FEAT_PYTHON3)
3116 v = 3;
3117# endif
3118 }
3119
3120 /*
3121 * now source, if required python version is not supported show
3122 * unobtrusive message.
3123 */
3124 if (eap == NULL)
3125 vim_memset(&ex, 0, sizeof(ex));
3126 else
3127 ex = *eap;
3128 ex.arg = fname;
3129 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3130
3131 if (v == 2)
3132 {
3133# ifdef FEAT_PYTHON
3134 ex_pyfile(&ex);
3135# else
3136 vim_snprintf((char *)IObuff, IOSIZE,
3137 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3138 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003139 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003140# endif
3141 return;
3142 }
3143 else
3144 {
3145# ifdef FEAT_PYTHON3
3146 ex_py3file(&ex);
3147# else
3148 vim_snprintf((char *)IObuff, IOSIZE,
3149 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3150 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003151 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003152# endif
3153 return;
3154 }
3155}
3156
3157/*
3158 * ":pyxfile {fname}"
3159 */
3160 void
3161ex_pyxfile(exarg_T *eap)
3162{
3163 source_pyx_file(eap, eap->arg);
3164}
3165
3166/*
3167 * ":pyx"
3168 */
3169 void
3170ex_pyx(exarg_T *eap)
3171{
3172# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3173 init_pyxversion();
3174 if (p_pyx == 2)
3175 ex_python(eap);
3176 else
3177 ex_py3(eap);
3178# elif defined(FEAT_PYTHON)
3179 ex_python(eap);
3180# elif defined(FEAT_PYTHON3)
3181 ex_py3(eap);
3182# endif
3183}
3184
3185/*
3186 * ":pyxdo"
3187 */
3188 void
3189ex_pyxdo(exarg_T *eap)
3190{
3191# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3192 init_pyxversion();
3193 if (p_pyx == 2)
3194 ex_pydo(eap);
3195 else
3196 ex_py3do(eap);
3197# elif defined(FEAT_PYTHON)
3198 ex_pydo(eap);
3199# elif defined(FEAT_PYTHON3)
3200 ex_py3do(eap);
3201# endif
3202}
3203
3204#endif
3205
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206/*
3207 * ":source {fname}"
3208 */
3209 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003210ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211{
3212#ifdef FEAT_BROWSE
3213 if (cmdmod.browse)
3214 {
3215 char_u *fname = NULL;
3216
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003217 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02003218 NULL, NULL,
3219 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 if (fname != NULL)
3221 {
3222 cmd_source(fname, eap);
3223 vim_free(fname);
3224 }
3225 }
3226 else
3227#endif
3228 cmd_source(eap->arg, eap);
3229}
3230
3231 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003232cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233{
3234 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003235 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003238 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003239 * Need to execute the commands directly. This is required at least
3240 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 * - ":g" command busy
3242 * - after ":argdo", ":windo" or ":bufdo"
3243 * - another command follows
3244 * - inside a loop
3245 */
3246 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3247#ifdef FEAT_EVAL
3248 || eap->cstack->cs_idx >= 0
3249#endif
3250 );
3251
3252 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003253 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003254 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255}
3256
3257/*
3258 * ":source" and associated commands.
3259 */
3260/*
3261 * Structure used to store info for each sourced file.
3262 * It is shared between do_source() and getsourceline().
3263 * This is required, because it needs to be handed to do_cmdline() and
3264 * sourcing can be done recursively.
3265 */
3266struct source_cookie
3267{
3268 FILE *fp; /* opened file for sourcing */
3269 char_u *nextline; /* if not NULL: line that was read ahead */
3270 int finished; /* ":finish" used */
Bram Moolenaar00590742019-02-15 21:06:09 +01003271#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3273 int error; /* TRUE if LF found after CR-LF */
3274#endif
3275#ifdef FEAT_EVAL
3276 linenr_T breakpoint; /* next line with breakpoint or zero */
3277 char_u *fname; /* name of sourced file */
3278 int dbg_tick; /* debug_tick when breakpoint was set */
3279 int level; /* top nesting level of sourced file */
3280#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003281 vimconv_T conv; /* type of conversion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282};
3283
3284#ifdef FEAT_EVAL
3285/*
3286 * Return the address holding the next breakpoint line for a source cookie.
3287 */
3288 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003289source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290{
3291 return &((struct source_cookie *)cookie)->breakpoint;
3292}
3293
3294/*
3295 * Return the address holding the debug tick for a source cookie.
3296 */
3297 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003298source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299{
3300 return &((struct source_cookie *)cookie)->dbg_tick;
3301}
3302
3303/*
3304 * Return the nesting level for a source cookie.
3305 */
3306 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003307source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003308{
3309 return ((struct source_cookie *)cookie)->level;
3310}
3311#endif
3312
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003313static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314
Bram Moolenaar4f974752019-02-17 17:44:42 +01003315#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003316# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317/*
3318 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003319 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320 */
3321 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003322fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003324# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003325 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3326# else
3327 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003328# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329
3330 if (fd_tmp == -1)
3331 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003332
3333# ifdef HAVE_FD_CLOEXEC
3334 {
3335 int fdflags = fcntl(fd_tmp, F_GETFD);
3336 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003337 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003338 }
3339# endif
3340
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 return fdopen(fd_tmp, READBIN);
3342}
3343#endif
3344
3345
3346/*
3347 * do_source: Read the file "fname" and execute its lines as EX commands.
3348 *
3349 * This function may be called recursively!
3350 *
3351 * return FAIL if file could not be opened, OK otherwise
3352 */
3353 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003354do_source(
3355 char_u *fname,
3356 int check_other, /* check for .vimrc and _vimrc */
3357 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358{
3359 struct source_cookie cookie;
3360 char_u *save_sourcing_name;
3361 linenr_T save_sourcing_lnum;
3362 char_u *p;
3363 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003364 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365 int retval = FAIL;
3366#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003367 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003369 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003370 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003372 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003374 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 int stat_ok;
3376# endif
3377#endif
3378#ifdef STARTUPTIME
3379 struct timeval tv_rel;
3380 struct timeval tv_start;
3381#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003382#ifdef FEAT_PROFILE
3383 proftime_T wait_start;
3384#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003385 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003386
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388 if (p == NULL)
3389 return retval;
3390 fname_exp = fix_fname(p);
3391 vim_free(p);
3392 if (fname_exp == NULL)
3393 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 if (mch_isdir(fname_exp))
3395 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003396 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397 goto theend;
3398 }
3399
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003400 /* Apply SourceCmd autocommands, they should get the file and source it. */
3401 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3402 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3403 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003404 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003405#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003406 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003407#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003408 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003409#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003410 if (retval == OK)
3411 // Apply SourcePost autocommands.
3412 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
3413 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003414 goto theend;
3415 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003416
3417 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003418 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003419
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003420#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3422#else
3423 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3424#endif
3425 if (cookie.fp == NULL && check_other)
3426 {
3427 /*
3428 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3429 * and ".exrc" by "_exrc" or vice versa.
3430 */
3431 p = gettail(fname_exp);
3432 if ((*p == '.' || *p == '_')
3433 && (STRICMP(p + 1, "vimrc") == 0
3434 || STRICMP(p + 1, "gvimrc") == 0
3435 || STRICMP(p + 1, "exrc") == 0))
3436 {
3437 if (*p == '_')
3438 *p = '.';
3439 else
3440 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003441#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3443#else
3444 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3445#endif
3446 }
3447 }
3448
3449 if (cookie.fp == NULL)
3450 {
3451 if (p_verbose > 0)
3452 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003453 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003455 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003457 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003458 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003459 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460 }
3461 goto theend;
3462 }
3463
3464 /*
3465 * The file exists.
3466 * - In verbose mode, give a message.
3467 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3468 */
3469 if (p_verbose > 1)
3470 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003471 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003473 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003475 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003476 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003477 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003479 if (is_vimrc == DOSO_VIMRC)
3480 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3481 else if (is_vimrc == DOSO_GVIMRC)
3482 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483
3484#ifdef USE_CRNL
3485 /* If no automatic file format: Set default to CR-NL. */
3486 if (*p_ffs == NUL)
3487 cookie.fileformat = EOL_DOS;
3488 else
3489 cookie.fileformat = EOL_UNKNOWN;
3490 cookie.error = FALSE;
3491#endif
3492
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 cookie.nextline = NULL;
3494 cookie.finished = FALSE;
3495
3496#ifdef FEAT_EVAL
3497 /*
3498 * Check if this script has a breakpoint.
3499 */
3500 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3501 cookie.fname = fname_exp;
3502 cookie.dbg_tick = debug_tick;
3503
3504 cookie.level = ex_nesting_level;
3505#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506
3507 /*
3508 * Keep the sourcing name/lnum, for recursive calls.
3509 */
3510 save_sourcing_name = sourcing_name;
3511 sourcing_name = fname_exp;
3512 save_sourcing_lnum = sourcing_lnum;
3513 sourcing_lnum = 0;
3514
3515#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003516 if (time_fd != NULL)
3517 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518#endif
3519
3520#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003521# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003522 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003523 prof_child_enter(&wait_start); /* entering a child now */
3524# endif
3525
3526 /* Don't use local function variables, if called from a function.
3527 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003528 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003529
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003530 save_current_sctx = current_sctx;
3531 current_sctx.sc_lnum = 0;
3532 current_sctx.sc_version = 1;
3533
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003534 // Check if this script was sourced before to finds its SID.
3535 // If it's new, generate a new SID.
3536 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003537 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538# ifdef UNIX
3539 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3540# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003541 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
3542 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003543 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003544 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003545 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546 && (
3547# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003548 /* Compare dev/ino when possible, it catches symbolic
3549 * links. Also compare file names, the inode may change
3550 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003551 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003552 && (si->sn_dev == st.st_dev
3553 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003555 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003556 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003557 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003558 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003559 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003560 current_sctx.sc_sid = ++last_current_SID;
3561 if (ga_grow(&script_items,
3562 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003563 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003564 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003566 ++script_items.ga_len;
3567 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3568# ifdef FEAT_PROFILE
3569 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003570# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003572 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003573 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01003574 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00003575# ifdef UNIX
3576 if (stat_ok)
3577 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003578 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003579 si->sn_dev = st.st_dev;
3580 si->sn_ino = st.st_ino;
3581 }
3582 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003583 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003584# endif
3585
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003587 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 }
3589
Bram Moolenaar05159a02005-02-26 23:04:13 +00003590# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003591 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003592 {
3593 int forceit;
3594
3595 /* Check if we do profiling for this script. */
3596 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3597 {
3598 script_do_profile(si);
3599 si->sn_pr_force = forceit;
3600 }
3601 if (si->sn_prof_on)
3602 {
3603 ++si->sn_pr_count;
3604 profile_start(&si->sn_pr_start);
3605 profile_zero(&si->sn_pr_children);
3606 }
3607 }
3608# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609#endif
3610
Bram Moolenaar67435d92017-10-19 21:04:37 +02003611 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3612
3613 /* Read the first line so we can check for a UTF-8 BOM. */
3614 firstline = getsourceline(0, (void *)&cookie, 0);
3615 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3616 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3617 {
3618 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3619 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3620 p = string_convert(&cookie.conv, firstline + 3, NULL);
3621 if (p == NULL)
3622 p = vim_strsave(firstline + 3);
3623 if (p != NULL)
3624 {
3625 vim_free(firstline);
3626 firstline = p;
3627 }
3628 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02003629
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630 /*
3631 * Call do_cmdline, which will call getsourceline() to get the lines.
3632 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003633 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003634 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003636
3637#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003638 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003639 {
3640 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003641 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003642 if (si->sn_prof_on)
3643 {
3644 profile_end(&si->sn_pr_start);
3645 profile_sub_wait(&wait_start, &si->sn_pr_start);
3646 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003647 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3648 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003649 }
3650 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651#endif
3652
3653 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003654 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655 sourcing_name = save_sourcing_name;
3656 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657 if (p_verbose > 1)
3658 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003659 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003660 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003662 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003663 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664 }
3665#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003666 if (time_fd != NULL)
3667 {
3668 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3669 time_msg((char *)IObuff, &tv_start);
3670 time_pop(&tv_rel);
3671 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672#endif
3673
Bram Moolenaar2b618522019-01-12 13:26:03 +01003674 if (!got_int)
3675 trigger_source_post = TRUE;
3676
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677#ifdef FEAT_EVAL
3678 /*
3679 * After a "finish" in debug mode, need to break at first command of next
3680 * sourced file.
3681 */
3682 if (save_debug_break_level > ex_nesting_level
3683 && debug_break_level == ex_nesting_level)
3684 ++debug_break_level;
3685#endif
3686
Bram Moolenaar05159a02005-02-26 23:04:13 +00003687#ifdef FEAT_EVAL
3688almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003689 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003690 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003691# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003692 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003693 prof_child_exit(&wait_start); /* leaving a child now */
3694# endif
3695#endif
3696 fclose(cookie.fp);
3697 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003698 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003699 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003700
Bram Moolenaar2b618522019-01-12 13:26:03 +01003701 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003702 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003703
Bram Moolenaar071d4272004-06-13 20:20:40 +00003704theend:
3705 vim_free(fname_exp);
3706 return retval;
3707}
3708
3709#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003710
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711/*
3712 * ":scriptnames"
3713 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003715ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716{
3717 int i;
3718
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003719 if (eap->addr_count > 0)
3720 {
3721 // :script {scriptId}: edit the script
3722 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003723 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003724 else
3725 {
3726 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3727 do_exedit(eap, NULL);
3728 }
3729 return;
3730 }
3731
Bram Moolenaar05159a02005-02-26 23:04:13 +00003732 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3733 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003734 {
3735 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3736 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003737 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003738 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739}
3740
3741# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3742/*
3743 * Fix slashes in the list of script names for 'shellslash'.
3744 */
3745 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003746scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003747{
3748 int i;
3749
Bram Moolenaar05159a02005-02-26 23:04:13 +00003750 for (i = 1; i <= script_items.ga_len; ++i)
3751 if (SCRIPT_ITEM(i).sn_name != NULL)
3752 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753}
3754# endif
3755
3756/*
3757 * Get a pointer to a script name. Used for ":verbose set".
3758 */
3759 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003760get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761{
3762 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003763 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003765 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003766 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003767 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003768 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003769 return (char_u *)_("environment variable");
3770 if (id == SID_ERROR)
3771 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003772 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003773}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003774
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003775# if defined(EXITFREE) || defined(PROTO)
3776 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003777free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003778{
3779 int i;
3780
3781 for (i = script_items.ga_len; i > 0; --i)
3782 vim_free(SCRIPT_ITEM(i).sn_name);
3783 ga_clear(&script_items);
3784}
3785# endif
3786
Bram Moolenaar071d4272004-06-13 20:20:40 +00003787#endif
3788
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789/*
3790 * Get one full line from a sourced file.
3791 * Called by do_cmdline() when it's called from do_source().
3792 *
3793 * Return a pointer to the line in allocated memory.
3794 * Return NULL for end-of-file or some error.
3795 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003797getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798{
3799 struct source_cookie *sp = (struct source_cookie *)cookie;
3800 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003801 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802
3803#ifdef FEAT_EVAL
3804 /* If breakpoints have been added/deleted need to check for it. */
3805 if (sp->dbg_tick < debug_tick)
3806 {
3807 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3808 sp->dbg_tick = debug_tick;
3809 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003810# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003811 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003812 script_line_end();
3813# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814#endif
3815 /*
3816 * Get current line. If there is a read-ahead line, use it, otherwise get
3817 * one now.
3818 */
3819 if (sp->finished)
3820 line = NULL;
3821 else if (sp->nextline == NULL)
3822 line = get_one_sourceline(sp);
3823 else
3824 {
3825 line = sp->nextline;
3826 sp->nextline = NULL;
3827 ++sourcing_lnum;
3828 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003829#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003830 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003831 script_line_start();
3832#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833
3834 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3835 * contain the 'C' flag. */
3836 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3837 {
3838 /* compensate for the one line read-ahead */
3839 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003840
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003841 // Get the next line and concatenate it when it starts with a
3842 // backslash. We always need to read the next line, keep it in
3843 // sp->nextline.
3844 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003845 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003846 if (sp->nextline != NULL
3847 && (*(p = skipwhite(sp->nextline)) == '\\'
3848 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003850 garray_T ga;
3851
Bram Moolenaarb549a732012-02-22 18:29:33 +01003852 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003853 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003854 if (*p == '\\')
3855 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003856 for (;;)
3857 {
3858 vim_free(sp->nextline);
3859 sp->nextline = get_one_sourceline(sp);
3860 if (sp->nextline == NULL)
3861 break;
3862 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003863 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003864 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003865 // Adjust the growsize to the current length to speed up
3866 // concatenating many lines.
3867 if (ga.ga_len > 400)
3868 {
3869 if (ga.ga_len > 8000)
3870 ga.ga_growsize = 8000;
3871 else
3872 ga.ga_growsize = ga.ga_len;
3873 }
3874 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003875 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003876 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3877 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003878 }
3879 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003881 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003882 }
3883 }
3884
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3886 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003887 char_u *s;
3888
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889 /* Convert the encoding of the script line. */
3890 s = string_convert(&sp->conv, line, NULL);
3891 if (s != NULL)
3892 {
3893 vim_free(line);
3894 line = s;
3895 }
3896 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897
3898#ifdef FEAT_EVAL
3899 /* Did we encounter a breakpoint? */
3900 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3901 {
3902 dbg_breakpoint(sp->fname, sourcing_lnum);
3903 /* Find next breakpoint. */
3904 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3905 sp->dbg_tick = debug_tick;
3906 }
3907#endif
3908
3909 return line;
3910}
3911
3912 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003913get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003914{
3915 garray_T ga;
3916 int len;
3917 int c;
3918 char_u *buf;
3919#ifdef USE_CRNL
3920 int has_cr; /* CR-LF found */
3921#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003922 int have_read = FALSE;
3923
3924 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003925 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926
3927 /*
3928 * Loop until there is a finished line (or end-of-file).
3929 */
3930 sourcing_lnum++;
3931 for (;;)
3932 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003933 /* make room to read at least 120 (more) characters */
3934 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003935 break;
3936 buf = (char_u *)ga.ga_data;
3937
Bram Moolenaar00590742019-02-15 21:06:09 +01003938 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003939 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003940 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003941 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942#ifdef USE_CRNL
3943 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3944 * CTRL-Z by its own, or after a NL. */
3945 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3946 && sp->fileformat == EOL_DOS
3947 && buf[len - 1] == Ctrl_Z)
3948 {
3949 buf[len - 1] = NUL;
3950 break;
3951 }
3952#endif
3953
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 ga.ga_len = len;
3956
3957 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003958 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959 continue;
3960
3961 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3962 {
3963#ifdef USE_CRNL
3964 has_cr = (len >= 2 && buf[len - 2] == '\r');
3965 if (sp->fileformat == EOL_UNKNOWN)
3966 {
3967 if (has_cr)
3968 sp->fileformat = EOL_DOS;
3969 else
3970 sp->fileformat = EOL_UNIX;
3971 }
3972
3973 if (sp->fileformat == EOL_DOS)
3974 {
3975 if (has_cr) /* replace trailing CR */
3976 {
3977 buf[len - 2] = '\n';
3978 --len;
3979 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980 }
3981 else /* lines like ":map xx yy^M" will have failed */
3982 {
3983 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003984 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003985 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003986 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003987 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 sp->error = TRUE;
3989 sp->fileformat = EOL_UNIX;
3990 }
3991 }
3992#endif
3993 /* The '\n' is escaped if there is an odd number of ^V's just
3994 * before it, first set "c" just before the 'V's and then check
3995 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3996 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3997 ;
3998 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3999 {
4000 sourcing_lnum++;
4001 continue;
4002 }
4003
4004 buf[len - 1] = NUL; /* remove the NL */
4005 }
4006
4007 /*
4008 * Check for ^C here now and then, so recursive :so can be broken.
4009 */
4010 line_breakcheck();
4011 break;
4012 }
4013
4014 if (have_read)
4015 return (char_u *)ga.ga_data;
4016
4017 vim_free(ga.ga_data);
4018 return NULL;
4019}
4020
Bram Moolenaar05159a02005-02-26 23:04:13 +00004021#if defined(FEAT_PROFILE) || defined(PROTO)
4022/*
4023 * Called when starting to read a script line.
4024 * "sourcing_lnum" must be correct!
4025 * When skipping lines it may not actually be executed, but we won't find out
4026 * until later and we need to store the time now.
4027 */
4028 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004029script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004030{
4031 scriptitem_T *si;
4032 sn_prl_T *pp;
4033
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004034 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004035 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004036 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004037 if (si->sn_prof_on && sourcing_lnum >= 1)
4038 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004039 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004040 * here isn't counted. */
Bram Moolenaar67435d92017-10-19 21:04:37 +02004041 (void)ga_grow(&si->sn_prl_ga,
4042 (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004043 si->sn_prl_idx = sourcing_lnum - 1;
4044 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4045 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4046 {
4047 /* Zero counters for a line that was not used before. */
4048 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4049 pp->snp_count = 0;
4050 profile_zero(&pp->sn_prl_total);
4051 profile_zero(&pp->sn_prl_self);
4052 ++si->sn_prl_ga.ga_len;
4053 }
4054 si->sn_prl_execed = FALSE;
4055 profile_start(&si->sn_prl_start);
4056 profile_zero(&si->sn_prl_children);
4057 profile_get_wait(&si->sn_prl_wait);
4058 }
4059}
4060
4061/*
4062 * Called when actually executing a function line.
4063 */
4064 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004065script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004066{
4067 scriptitem_T *si;
4068
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004069 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004070 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004071 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004072 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4073 si->sn_prl_execed = TRUE;
4074}
4075
4076/*
Bram Moolenaar67435d92017-10-19 21:04:37 +02004077 * Called when done with a script line.
Bram Moolenaar05159a02005-02-26 23:04:13 +00004078 */
4079 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004080script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004081{
4082 scriptitem_T *si;
4083 sn_prl_T *pp;
4084
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004085 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004086 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004087 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004088 if (si->sn_prof_on && si->sn_prl_idx >= 0
4089 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4090 {
4091 if (si->sn_prl_execed)
4092 {
4093 pp = &PRL_ITEM(si, si->sn_prl_idx);
4094 ++pp->snp_count;
4095 profile_end(&si->sn_prl_start);
4096 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004097 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004098 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4099 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004100 }
4101 si->sn_prl_idx = -1;
4102 }
4103}
4104#endif
4105
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106/*
4107 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004109 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004110ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004111{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 struct source_cookie *sp;
4113 char_u *name;
4114
4115 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4116 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004117 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 return;
4119 }
4120
4121 if (*eap->arg != NUL)
4122 {
4123 name = enc_canonize(eap->arg);
4124 if (name == NULL) /* out of memory */
4125 return;
4126 }
4127 else
4128 name = eap->arg;
4129
4130 /* Setup for conversion from the specified encoding to 'encoding'. */
4131 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4132 convert_setup(&sp->conv, name, p_enc);
4133
4134 if (name != eap->arg)
4135 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136}
4137
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004138/*
4139 * ":scriptversion": Set Vim script version for a sourced script.
4140 */
4141 void
4142ex_scriptversion(exarg_T *eap UNUSED)
4143{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004144#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004145 int nr;
4146
4147 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4148 {
4149 emsg(_("E984: :scriptversion used outside of a sourced file"));
4150 return;
4151 }
4152
4153 nr = getdigits(&eap->arg);
4154 if (nr == 0 || *eap->arg != NUL)
4155 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02004156 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004157 semsg(_("E999: scriptversion not supported: %d"), nr);
4158 else
4159 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004160#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004161}
4162
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163#if defined(FEAT_EVAL) || defined(PROTO)
4164/*
4165 * ":finish": Mark a sourced file as finished.
4166 */
4167 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004168ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169{
4170 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4171 do_finish(eap, FALSE);
4172 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004173 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174}
4175
4176/*
4177 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4178 * Also called for a pending finish at the ":endtry" or after returning from
4179 * an extra do_cmdline(). "reanimate" is used in the latter case.
4180 */
4181 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004182do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183{
4184 int idx;
4185
4186 if (reanimate)
4187 ((struct source_cookie *)getline_cookie(eap->getline,
4188 eap->cookie))->finished = FALSE;
4189
4190 /*
4191 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4192 * not in its finally clause (which then is to be executed next) is found.
4193 * In this case, make the ":finish" pending for execution at the ":endtry".
4194 * Otherwise, finish normally.
4195 */
4196 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4197 if (idx >= 0)
4198 {
4199 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4200 report_make_pending(CSTP_FINISH, NULL);
4201 }
4202 else
4203 ((struct source_cookie *)getline_cookie(eap->getline,
4204 eap->cookie))->finished = TRUE;
4205}
4206
4207
4208/*
4209 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4210 * message for missing ":endif".
4211 * Return FALSE when not sourcing a file.
4212 */
4213 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004214source_finished(
4215 char_u *(*fgetline)(int, void *, int),
4216 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004217{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004218 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004220 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221}
4222#endif
4223
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224/*
4225 * ":checktime [buffer]"
4226 */
4227 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004228ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229{
4230 buf_T *buf;
4231 int save_no_check_timestamps = no_check_timestamps;
4232
4233 no_check_timestamps = 0;
4234 if (eap->addr_count == 0) /* default is all buffers */
4235 check_timestamps(FALSE);
4236 else
4237 {
4238 buf = buflist_findnr((int)eap->line2);
4239 if (buf != NULL) /* cannot happen? */
4240 (void)buf_check_timestamp(buf, FALSE);
4241 }
4242 no_check_timestamps = save_no_check_timestamps;
4243}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004244
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4246 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004247# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004248 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004249get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004251 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004253 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004254 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255
Bram Moolenaar4f974752019-02-17 17:44:42 +01004256# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 if (loc != NULL)
4258 {
4259 char_u *p;
4260
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004261 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4262 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263 p = vim_strchr(loc, '=');
4264 if (p != NULL)
4265 {
4266 loc = ++p;
4267 while (*p != NUL) /* remove trailing newline */
4268 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004269 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270 {
4271 *p = NUL;
4272 break;
4273 }
4274 ++p;
4275 }
4276 }
4277 }
4278# endif
4279
4280 return loc;
4281}
4282#endif
4283
4284
Bram Moolenaar4f974752019-02-17 17:44:42 +01004285#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286/*
4287 * On MS-Windows locale names are strings like "German_Germany.1252", but
4288 * gettext expects "de". Try to translate one into another here for a few
4289 * supported languages.
4290 */
4291 static char_u *
4292gettext_lang(char_u *name)
4293{
4294 int i;
4295 static char *(mtable[]) = {
4296 "afrikaans", "af",
4297 "czech", "cs",
4298 "dutch", "nl",
4299 "german", "de",
4300 "english_united kingdom", "en_GB",
4301 "spanish", "es",
4302 "french", "fr",
4303 "italian", "it",
4304 "japanese", "ja",
4305 "korean", "ko",
4306 "norwegian", "no",
4307 "polish", "pl",
4308 "russian", "ru",
4309 "slovak", "sk",
4310 "swedish", "sv",
4311 "ukrainian", "uk",
4312 "chinese_china", "zh_CN",
4313 "chinese_taiwan", "zh_TW",
4314 NULL};
4315
4316 for (i = 0; mtable[i] != NULL; i += 2)
4317 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004318 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 return name;
4320}
4321#endif
4322
4323#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4324/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01004325 * Return TRUE when "lang" starts with a valid language name.
4326 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
4327 */
4328 static int
4329is_valid_mess_lang(char_u *lang)
4330{
4331 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
4332}
4333
4334/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 * Obtain the current messages language. Used to set the default for
4336 * 'helplang'. May return NULL or an empty string.
4337 */
4338 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004339get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340{
4341 char_u *p;
4342
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004343# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004345 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346# else
4347 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004348 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4349 * and LC_MONETARY may be set differently for a Japanese working in the
4350 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004351 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352# endif
4353# else
4354 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004355 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356 {
4357 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004358 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 p = mch_getenv((char_u *)"LANG");
4360 }
4361# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004362# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 p = gettext_lang(p);
4364# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01004365 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366}
4367#endif
4368
Bram Moolenaardef9e822004-12-31 20:58:58 +00004369/* Complicated #if; matches with where get_mess_env() is used below. */
4370#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4371 && defined(LC_MESSAGES))) \
4372 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00004373 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374/*
4375 * Get the language used for messages from the environment.
4376 */
4377 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004378get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004379{
4380 char_u *p;
4381
4382 p = mch_getenv((char_u *)"LC_ALL");
4383 if (p == NULL || *p == NUL)
4384 {
4385 p = mch_getenv((char_u *)"LC_MESSAGES");
4386 if (p == NULL || *p == NUL)
4387 {
4388 p = mch_getenv((char_u *)"LANG");
4389 if (p != NULL && VIM_ISDIGIT(*p))
4390 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004391# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004393 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394# endif
4395 }
4396 }
4397 return p;
4398}
4399#endif
4400
4401#if defined(FEAT_EVAL) || defined(PROTO)
4402
4403/*
4404 * Set the "v:lang" variable according to the current locale setting.
4405 * Also do "v:lc_time"and "v:ctype".
4406 */
4407 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004408set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409{
4410 char_u *loc;
4411
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004412# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004413 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414# else
4415 /* setlocale() not supported: use the default value */
4416 loc = (char_u *)"C";
4417# endif
4418 set_vim_var_string(VV_CTYPE, loc, -1);
4419
4420 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4421 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004422# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004423 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424# else
4425 loc = get_mess_env();
4426# endif
4427 set_vim_var_string(VV_LANG, loc, -1);
4428
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004429# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004430 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431# endif
4432 set_vim_var_string(VV_LC_TIME, loc, -1);
4433}
4434#endif
4435
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01004436#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437/*
4438 * ":language": Set the language (locale).
4439 */
4440 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004441ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442{
4443 char *loc;
4444 char_u *p;
4445 char_u *name;
4446 int what = LC_ALL;
4447 char *whatstr = "";
4448#ifdef LC_MESSAGES
4449# define VIM_LC_MESSAGES LC_MESSAGES
4450#else
4451# define VIM_LC_MESSAGES 6789
4452#endif
4453
4454 name = eap->arg;
4455
4456 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4457 * Allow abbreviation, but require at least 3 characters to avoid
4458 * confusion with a two letter language name "me" or "ct". */
4459 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004460 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004461 {
4462 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4463 {
4464 what = VIM_LC_MESSAGES;
4465 name = skipwhite(p);
4466 whatstr = "messages ";
4467 }
4468 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4469 {
4470 what = LC_CTYPE;
4471 name = skipwhite(p);
4472 whatstr = "ctype ";
4473 }
4474 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4475 {
4476 what = LC_TIME;
4477 name = skipwhite(p);
4478 whatstr = "time ";
4479 }
4480 }
4481
4482 if (*name == NUL)
4483 {
4484#ifndef LC_MESSAGES
4485 if (what == VIM_LC_MESSAGES)
4486 p = get_mess_env();
4487 else
4488#endif
4489 p = (char_u *)setlocale(what, NULL);
4490 if (p == NULL || *p == NUL)
4491 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004492 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 }
4494 else
4495 {
4496#ifndef LC_MESSAGES
4497 if (what == VIM_LC_MESSAGES)
4498 loc = "";
4499 else
4500#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004501 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004503#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4504 /* Make sure strtod() uses a decimal point, not a comma. */
4505 setlocale(LC_NUMERIC, "C");
4506#endif
4507 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004509 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510 else
4511 {
4512#ifdef HAVE_NL_MSG_CAT_CNTR
4513 /* Need to do this for GNU gettext, otherwise cached translations
4514 * will be used again. */
4515 extern int _nl_msg_cat_cntr;
4516
4517 ++_nl_msg_cat_cntr;
4518#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004519 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4521
4522 if (what != LC_TIME)
4523 {
4524 /* Tell gettext() what to translate to. It apparently doesn't
4525 * use the currently effective locale. Also do this when
4526 * FEAT_GETTEXT isn't defined, so that shell commands use this
4527 * value. */
4528 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004529 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004531
4532 /* Clear $LANGUAGE because GNU gettext uses it. */
4533 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01004534# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004535 /* Apparently MS-Windows printf() may cause a crash when
4536 * we give it 8-bit text while it's expecting text in the
4537 * current locale. This call avoids that. */
4538 setlocale(LC_CTYPE, "C");
4539# endif
4540 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004541 if (what != LC_CTYPE)
4542 {
4543 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01004544#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545 mname = gettext_lang(name);
4546#else
4547 mname = name;
4548#endif
4549 vim_setenv((char_u *)"LC_MESSAGES", mname);
4550#ifdef FEAT_MULTI_LANG
4551 set_helplang_default(mname);
4552#endif
4553 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554 }
4555
4556# ifdef FEAT_EVAL
4557 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4558 set_lang_var();
4559# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004560# ifdef FEAT_TITLE
4561 maketitle();
4562# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 }
4564 }
4565}
4566
4567# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004568
4569static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004570
Bram Moolenaar4f974752019-02-17 17:44:42 +01004571# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004572static int did_init_locales = FALSE;
4573
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004574/* Return an array of strings for all available locales + NULL for the
4575 * last element. Return NULL in case of error. */
4576 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004577find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004578{
4579 garray_T locales_ga;
4580 char_u *loc;
4581
4582 /* Find all available locales by running command "locale -a". If this
4583 * doesn't work we won't have completion. */
4584 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004585 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004586 if (locale_a == NULL)
4587 return NULL;
4588 ga_init2(&locales_ga, sizeof(char_u *), 20);
4589
4590 /* Transform locale_a string where each locale is separated by "\n"
4591 * into an array of locale strings. */
4592 loc = (char_u *)strtok((char *)locale_a, "\n");
4593
4594 while (loc != NULL)
4595 {
4596 if (ga_grow(&locales_ga, 1) == FAIL)
4597 break;
4598 loc = vim_strsave(loc);
4599 if (loc == NULL)
4600 break;
4601
4602 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4603 loc = (char_u *)strtok(NULL, "\n");
4604 }
4605 vim_free(locale_a);
4606 if (ga_grow(&locales_ga, 1) == FAIL)
4607 {
4608 ga_clear(&locales_ga);
4609 return NULL;
4610 }
4611 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4612 return (char_u **)locales_ga.ga_data;
4613}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004614# endif
4615
4616/*
4617 * Lazy initialization of all available locales.
4618 */
4619 static void
4620init_locales(void)
4621{
Bram Moolenaar4f974752019-02-17 17:44:42 +01004622# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004623 if (!did_init_locales)
4624 {
4625 did_init_locales = TRUE;
4626 locales = find_locales();
4627 }
4628# endif
4629}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004630
4631# if defined(EXITFREE) || defined(PROTO)
4632 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004633free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004634{
4635 int i;
4636 if (locales != NULL)
4637 {
4638 for (i = 0; locales[i] != NULL; i++)
4639 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004640 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004641 }
4642}
4643# endif
4644
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645/*
4646 * Function given to ExpandGeneric() to obtain the possible arguments of the
4647 * ":language" command.
4648 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004650get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651{
4652 if (idx == 0)
4653 return (char_u *)"messages";
4654 if (idx == 1)
4655 return (char_u *)"ctype";
4656 if (idx == 2)
4657 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004658
4659 init_locales();
4660 if (locales == NULL)
4661 return NULL;
4662 return locales[idx - 3];
4663}
4664
4665/*
4666 * Function given to ExpandGeneric() to obtain the available locales.
4667 */
4668 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004669get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004670{
4671 init_locales();
4672 if (locales == NULL)
4673 return NULL;
4674 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004675}
4676# endif
4677
4678#endif