blob: 036a2a73523e163d61529885dd4d1420c61f2a6d [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 Moolenaar7d491c42019-06-25 06:28:02 +0200370 int save_must_redraw = must_redraw;
371 int save_trylevel = trylevel;
Bram Moolenaare723c422017-09-06 23:40:10 +0200372 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200373 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare96a2492019-06-25 04:12:16 +0200374 int save_may_garbage_collect = may_garbage_collect;
Bram Moolenaare723c422017-09-06 23:40:10 +0200375 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200376 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200377
Bram Moolenaare723c422017-09-06 23:40:10 +0200378 /* Create a scope for running the timer callback, ignoring most of
379 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200380 timer_busy = timer_busy > 0 || vgetc_busy > 0;
381 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +0200382 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200383 did_emsg = FALSE;
384 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200385 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +0200386 trylevel = 0;
387 did_throw = FALSE;
388 current_exception = NULL;
Bram Moolenaare96a2492019-06-25 04:12:16 +0200389 may_garbage_collect = FALSE;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200390 save_vimvars(&vvsave);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200391
Bram Moolenaar75537a92016-09-05 22:45:28 +0200392 timer->tr_firing = TRUE;
393 timer_callback(timer);
394 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200395
Bram Moolenaar75537a92016-09-05 22:45:28 +0200396 timer_next = timer->tr_next;
397 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200398 timer_busy = save_timer_busy;
399 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200400 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200401 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200402 did_emsg = save_did_emsg;
403 called_emsg = save_called_emsg;
404 trylevel = save_trylevel;
405 did_throw = save_did_throw;
406 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200407 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200408 if (must_redraw != 0)
409 need_update_screen = TRUE;
410 must_redraw = must_redraw > save_must_redraw
411 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200412 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200413 may_garbage_collect = save_may_garbage_collect;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200414
415 /* Only fire the timer again if it repeats and stop_timer() wasn't
416 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200417 if (timer->tr_repeat != 0 && timer->tr_id != -1
418 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200419 {
420 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100421 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200422 if (this_due < 1)
423 this_due = 1;
424 if (timer->tr_repeat > 0)
425 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100426 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200427 else
428 {
429 this_due = -1;
430 remove_timer(timer);
431 free_timer(timer);
432 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100433 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200434 if (this_due > 0 && (next_due == -1 || next_due > this_due))
435 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100436 }
437
438 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200439 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100440
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100441#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100442 if (bevalexpr_due_set)
443 {
444 this_due = proftime_time_left(&bevalexpr_due, &now);
445 if (this_due <= 1)
446 {
447 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100448 if (balloonEval == NULL)
449 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200450 balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100451 balloonEvalForTerm = TRUE;
452 }
453 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200454 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100455 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200456 setcursor();
457 out_flush();
458 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100459 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200460 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100461 next_due = this_due;
462 }
463#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200464#ifdef FEAT_TERMINAL
465 /* Some terminal windows may need their buffer updated. */
466 next_due = term_check_timers(next_due, &now);
467#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100468
Bram Moolenaar75537a92016-09-05 22:45:28 +0200469 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100470}
471
472/*
473 * Find a timer by ID. Returns NULL if not found;
474 */
475 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200476find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100477{
478 timer_T *timer;
479
Bram Moolenaar75537a92016-09-05 22:45:28 +0200480 if (id >= 0)
481 {
482 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
483 if (timer->tr_id == id)
484 return timer;
485 }
486 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100487}
488
489
490/*
491 * Stop a timer and delete it.
492 */
493 void
494stop_timer(timer_T *timer)
495{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200496 if (timer->tr_firing)
497 /* Free the timer after the callback returns. */
498 timer->tr_id = -1;
499 else
500 {
501 remove_timer(timer);
502 free_timer(timer);
503 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100504}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200505
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200506 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200507stop_all_timers(void)
508{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200509 timer_T *timer;
510 timer_T *timer_next;
511
512 for (timer = first_timer; timer != NULL; timer = timer_next)
513 {
514 timer_next = timer->tr_next;
515 stop_timer(timer);
516 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200517}
518
519 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200520add_timer_info(typval_T *rettv, timer_T *timer)
521{
522 list_T *list = rettv->vval.v_list;
523 dict_T *dict = dict_alloc();
524 dictitem_T *di;
525 long remaining;
526 proftime_T now;
527
528 if (dict == NULL)
529 return;
530 list_append_dict(list, dict);
531
Bram Moolenaare0be1672018-07-08 16:50:37 +0200532 dict_add_number(dict, "id", timer->tr_id);
533 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200534
535 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100536 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200537 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200538
Bram Moolenaare0be1672018-07-08 16:50:37 +0200539 dict_add_number(dict, "repeat",
540 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
541 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200542
543 di = dictitem_alloc((char_u *)"callback");
544 if (di != NULL)
545 {
546 if (dict_add(dict, di) == FAIL)
547 vim_free(di);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200548 else
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200549 put_callback(&timer->tr_callback, &di->di_tv);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200550 }
551}
552
553 void
554add_timer_info_all(typval_T *rettv)
555{
556 timer_T *timer;
557
558 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200559 if (timer->tr_id != -1)
560 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200561}
562
Bram Moolenaare3188e22016-05-31 21:13:04 +0200563/*
564 * Mark references in partials of timers.
565 */
566 int
567set_ref_in_timer(int copyID)
568{
569 int abort = FALSE;
570 timer_T *timer;
571 typval_T tv;
572
Bram Moolenaar75a1a942019-06-20 03:45:36 +0200573 for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
Bram Moolenaare3188e22016-05-31 21:13:04 +0200574 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200575 if (timer->tr_callback.cb_partial != NULL)
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200576 {
577 tv.v_type = VAR_PARTIAL;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200578 tv.vval.v_partial = timer->tr_callback.cb_partial;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200579 }
580 else
581 {
582 tv.v_type = VAR_FUNC;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200583 tv.vval.v_string = timer->tr_callback.cb_name;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200584 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200585 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
586 }
587 return abort;
588}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200589
590# if defined(EXITFREE) || defined(PROTO)
591 void
592timer_free_all()
593{
594 timer_T *timer;
595
596 while (first_timer != NULL)
597 {
598 timer = first_timer;
599 remove_timer(timer);
600 free_timer(timer);
601 }
602}
603# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100604# endif
605
Bram Moolenaar113e1072019-01-20 15:30:40 +0100606#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) && defined(FEAT_PROFILE)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200607# if defined(HAVE_MATH_H)
608# include <math.h>
609# endif
610
611/*
612 * Divide the time "tm" by "count" and store in "tm2".
613 */
614 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100615profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200616{
617 if (count == 0)
618 profile_zero(tm2);
619 else
620 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100621# ifdef MSWIN
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200622 tm2->QuadPart = tm->QuadPart / count;
623# else
624 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
625
626 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200627 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200628# endif
629 }
630}
631#endif
632
Bram Moolenaar76929292008-01-06 19:07:36 +0000633# if defined(FEAT_PROFILE) || defined(PROTO)
634/*
635 * Functions for profiling.
636 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100637static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +0000638static proftime_T prof_wait_time;
639
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000640/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000641 * Add the time "tm2" to "tm".
642 */
643 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100644profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000645{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100646# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000647 tm->QuadPart += tm2->QuadPart;
648# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000649 tm->tv_usec += tm2->tv_usec;
650 tm->tv_sec += tm2->tv_sec;
651 if (tm->tv_usec >= 1000000)
652 {
653 tm->tv_usec -= 1000000;
654 ++tm->tv_sec;
655 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000656# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000657}
658
659/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000660 * Add the "self" time from the total time and the children's time.
661 */
662 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100663profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +0000664{
665 /* Check that the result won't be negative. Can happen with recursive
666 * calls. */
Bram Moolenaar4f974752019-02-17 17:44:42 +0100667#ifdef MSWIN
Bram Moolenaar1056d982006-03-09 22:37:52 +0000668 if (total->QuadPart <= children->QuadPart)
669 return;
670#else
671 if (total->tv_sec < children->tv_sec
672 || (total->tv_sec == children->tv_sec
673 && total->tv_usec <= children->tv_usec))
674 return;
675#endif
676 profile_add(self, total);
677 profile_sub(self, children);
678}
679
680/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000681 * Get the current waittime.
682 */
683 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100684profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000685{
686 *tm = prof_wait_time;
687}
688
689/*
690 * Subtract the passed waittime since "tm" from "tma".
691 */
692 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100693profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000694{
695 proftime_T tm3 = prof_wait_time;
696
697 profile_sub(&tm3, tm);
698 profile_sub(tma, &tm3);
699}
700
701/*
702 * Return TRUE if "tm1" and "tm2" are equal.
703 */
704 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100705profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000706{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100707# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000708 return (tm1->QuadPart == tm2->QuadPart);
709# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000710 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000711# endif
712}
713
714/*
715 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
716 */
717 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100718profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000719{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100720# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000721 return (int)(tm2->QuadPart - tm1->QuadPart);
722# else
723 if (tm1->tv_sec == tm2->tv_sec)
724 return tm2->tv_usec - tm1->tv_usec;
725 return tm2->tv_sec - tm1->tv_sec;
726# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000727}
728
Bram Moolenaar05159a02005-02-26 23:04:13 +0000729static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000730static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000731
732/*
733 * ":profile cmd args"
734 */
735 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100736ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000737{
738 char_u *e;
739 int len;
740
741 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000742 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000743 e = skipwhite(e);
744
745 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
746 {
747 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +0200748 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000749 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000750 profile_zero(&prof_wait_time);
751 set_vim_var_nr(VV_PROFILING, 1L);
752 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000753 else if (do_profiling == PROF_NONE)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100754 emsg(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000755 else if (STRCMP(eap->arg, "pause") == 0)
756 {
757 if (do_profiling == PROF_YES)
758 profile_start(&pause_time);
759 do_profiling = PROF_PAUSED;
760 }
761 else if (STRCMP(eap->arg, "continue") == 0)
762 {
763 if (do_profiling == PROF_PAUSED)
764 {
765 profile_end(&pause_time);
766 profile_add(&prof_wait_time, &pause_time);
767 }
768 do_profiling = PROF_YES;
769 }
Bram Moolenaar05159a02005-02-26 23:04:13 +0000770 else
771 {
772 /* The rest is similar to ":breakadd". */
773 ex_breakadd(eap);
774 }
775}
776
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100777/* Command line expansion for :profile. */
778static enum
779{
780 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +0100781 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100782} pexpand_what;
783
784static char *pexpand_cmds[] = {
785 "start",
786#define PROFCMD_START 0
787 "pause",
788#define PROFCMD_PAUSE 1
789 "continue",
790#define PROFCMD_CONTINUE 2
791 "func",
792#define PROFCMD_FUNC 3
793 "file",
794#define PROFCMD_FILE 4
795 NULL
796#define PROFCMD_LAST 5
797};
798
799/*
800 * Function given to ExpandGeneric() to obtain the profile command
801 * specific expansion.
802 */
803 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100804get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100805{
806 switch (pexpand_what)
807 {
808 case PEXP_SUBCMD:
809 return (char_u *)pexpand_cmds[idx];
810 /* case PEXP_FUNC: TODO */
811 default:
812 return NULL;
813 }
814}
815
816/*
817 * Handle command line completion for :profile command.
818 */
819 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100820set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100821{
822 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100823
824 /* Default: expand subcommands. */
825 xp->xp_context = EXPAND_PROFILE;
826 pexpand_what = PEXP_SUBCMD;
827 xp->xp_pattern = arg;
828
829 end_subcmd = skiptowhite(arg);
830 if (*end_subcmd == NUL)
831 return;
832
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +0100833 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100834 {
835 xp->xp_context = EXPAND_FILES;
836 xp->xp_pattern = skipwhite(end_subcmd);
837 return;
838 }
839
840 /* TODO: expand function names after "func" */
841 xp->xp_context = EXPAND_NOTHING;
842}
843
Bram Moolenaar05159a02005-02-26 23:04:13 +0000844/*
845 * Dump the profiling info.
846 */
847 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100848profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000849{
850 FILE *fd;
851
852 if (profile_fname != NULL)
853 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000854 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000855 if (fd == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100856 semsg(_(e_notopen), profile_fname);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000857 else
858 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000859 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000860 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861 fclose(fd);
862 }
863 }
864}
865
866/*
867 * Start profiling script "fp".
868 */
869 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100870script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000871{
872 si->sn_pr_count = 0;
873 profile_zero(&si->sn_pr_total);
874 profile_zero(&si->sn_pr_self);
875
876 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
877 si->sn_prl_idx = -1;
878 si->sn_prof_on = TRUE;
879 si->sn_pr_nest = 0;
880}
881
882/*
Bram Moolenaar67435d92017-10-19 21:04:37 +0200883 * Save time when starting to invoke another script or function.
Bram Moolenaar05159a02005-02-26 23:04:13 +0000884 */
885 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100886script_prof_save(
887 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000888{
889 scriptitem_T *si;
890
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200891 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000892 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200893 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000894 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
895 profile_start(&si->sn_pr_child);
896 }
897 profile_get_wait(tm);
898}
899
900/*
901 * Count time spent in children after invoking another script or function.
902 */
903 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100904script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000905{
906 scriptitem_T *si;
907
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200908 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000909 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200910 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000911 if (si->sn_prof_on && --si->sn_pr_nest == 0)
912 {
913 profile_end(&si->sn_pr_child);
914 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
915 profile_add(&si->sn_pr_children, &si->sn_pr_child);
916 profile_add(&si->sn_prl_children, &si->sn_pr_child);
917 }
918 }
919}
920
921static proftime_T inchar_time;
922
923/*
924 * Called when starting to wait for the user to type a character.
925 */
926 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100927prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928{
929 profile_start(&inchar_time);
930}
931
932/*
933 * Called when finished waiting for the user to type a character.
934 */
935 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100936prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000937{
938 profile_end(&inchar_time);
939 profile_add(&prof_wait_time, &inchar_time);
940}
941
942/*
943 * Dump the profiling results for all scripts in file "fd".
944 */
945 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100946script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000947{
948 int id;
949 scriptitem_T *si;
950 int i;
951 FILE *sfd;
952 sn_prl_T *pp;
953
954 for (id = 1; id <= script_items.ga_len; ++id)
955 {
956 si = &SCRIPT_ITEM(id);
957 if (si->sn_prof_on)
958 {
959 fprintf(fd, "SCRIPT %s\n", si->sn_name);
960 if (si->sn_pr_count == 1)
961 fprintf(fd, "Sourced 1 time\n");
962 else
963 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
964 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
965 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
966 fprintf(fd, "\n");
967 fprintf(fd, "count total (s) self (s)\n");
968
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000969 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000970 if (sfd == NULL)
971 fprintf(fd, "Cannot open file!\n");
972 else
973 {
Bram Moolenaar67435d92017-10-19 21:04:37 +0200974 /* Keep going till the end of file, so that trailing
975 * continuation lines are listed. */
976 for (i = 0; ; ++i)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000977 {
978 if (vim_fgets(IObuff, IOSIZE, sfd))
979 break;
Bram Moolenaarac112f02017-12-05 16:46:28 +0100980 /* When a line has been truncated, append NL, taking care
981 * of multi-byte characters . */
982 if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
983 {
984 int n = IOSIZE - 2;
Bram Moolenaar13505972019-01-24 15:04:48 +0100985
Bram Moolenaarac112f02017-12-05 16:46:28 +0100986 if (enc_utf8)
987 {
988 /* Move to the first byte of this char.
989 * utf_head_off() doesn't work, because it checks
990 * for a truncated character. */
991 while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
992 --n;
993 }
994 else if (has_mbyte)
995 n -= mb_head_off(IObuff, IObuff + n);
Bram Moolenaarac112f02017-12-05 16:46:28 +0100996 IObuff[n] = NL;
997 IObuff[n + 1] = NUL;
998 }
Bram Moolenaar67435d92017-10-19 21:04:37 +0200999 if (i < si->sn_prl_ga.ga_len
1000 && (pp = &PRL_ITEM(si, i))->snp_count > 0)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001001 {
1002 fprintf(fd, "%5d ", pp->snp_count);
1003 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1004 fprintf(fd, " ");
1005 else
1006 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1007 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1008 }
1009 else
1010 fprintf(fd, " ");
1011 fprintf(fd, "%s", IObuff);
1012 }
1013 fclose(sfd);
1014 }
1015 fprintf(fd, "\n");
1016 }
1017 }
1018}
1019
1020/*
1021 * Return TRUE when a function defined in the current script should be
1022 * profiled.
1023 */
1024 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001025prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001026{
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001027 if (current_sctx.sc_sid > 0)
1028 return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001029 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001030}
1031
1032# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033#endif
1034
1035/*
1036 * If 'autowrite' option set, try to write the file.
1037 * Careful: autocommands may make "buf" invalid!
1038 *
1039 * return FAIL for failure, OK otherwise
1040 */
1041 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001042autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001044 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001045 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001046
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047 if (!(p_aw || p_awa) || !p_write
1048#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001049 /* never autowrite a "nofile" or "nowrite" buffer */
1050 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001052 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001054 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001055 r = buf_write_all(buf, forceit);
1056
1057 /* Writing may succeed but the buffer still changed, e.g., when there is a
1058 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001059 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001060 r = FAIL;
1061 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062}
1063
1064/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001065 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 */
1067 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001068autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069{
1070 buf_T *buf;
1071
1072 if (!(p_aw || p_awa) || !p_write)
1073 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001074 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001075 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001077 bufref_T bufref;
1078
1079 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001080
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001082
Bram Moolenaar071d4272004-06-13 20:20:40 +00001083 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001084 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086 }
1087}
1088
1089/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001090 * Return TRUE if buffer was changed and cannot be abandoned.
1091 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001094check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001096 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001097 bufref_T bufref;
1098
1099 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001100
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 if ( !forceit
1102 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001103 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1104 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 {
1106#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1107 if ((p_confirm || cmdmod.confirm) && p_write)
1108 {
1109 buf_T *buf2;
1110 int count = 0;
1111
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001112 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001113 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114 if (bufIsChanged(buf2)
1115 && (buf2->b_ffname != NULL
1116# ifdef FEAT_BROWSE
1117 || cmdmod.browse
1118# endif
1119 ))
1120 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001121 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001122 /* Autocommand deleted buffer, oops! It's not changed now. */
1123 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001124
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001126
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001127 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 /* Autocommand deleted buffer, oops! It's not changed now. */
1129 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001130 return bufIsChanged(buf);
1131 }
1132#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001133 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +02001134 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001135 else
Bram Moolenaar7a760922018-02-19 23:10:02 +01001136 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137 return TRUE;
1138 }
1139 return FALSE;
1140}
1141
1142#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1143
1144#if defined(FEAT_BROWSE) || defined(PROTO)
1145/*
1146 * When wanting to write a file without a file name, ask the user for a name.
1147 */
1148 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001149browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150{
1151 if (buf->b_fname == NULL)
1152 {
1153 char_u *fname;
1154
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001155 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1156 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 if (fname != NULL)
1158 {
1159 if (setfname(buf, fname, NULL, TRUE) == OK)
1160 buf->b_flags |= BF_NOTEDITED;
1161 vim_free(fname);
1162 }
1163 }
1164}
1165#endif
1166
1167/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001168 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001169 * Must check 'write' option first!
1170 */
1171 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001172dialog_changed(
1173 buf_T *buf,
1174 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001176 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177 int ret;
1178 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001179 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +02001181 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182 if (checkall)
1183 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1184 else
1185 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1186
Bram Moolenaar4ca41532019-05-09 21:48:37 +02001187 // Init ea pseudo-structure, this is needed for the check_overwrite()
1188 // function.
1189 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +02001190
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191 if (ret == VIM_YES)
1192 {
1193#ifdef FEAT_BROWSE
1194 /* May get file name, when there is none */
1195 browse_save_fname(buf);
1196#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001197 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1198 buf->b_fname, buf->b_ffname, FALSE) == OK)
1199 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200 (void)buf_write_all(buf, FALSE);
1201 }
1202 else if (ret == VIM_NO)
1203 {
Bram Moolenaarc024b462019-06-08 18:07:21 +02001204 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205 }
1206 else if (ret == VIM_ALL)
1207 {
1208 /*
1209 * Write all modified files that can be written.
1210 * Skip readonly buffers, these need to be confirmed
1211 * individually.
1212 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001213 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001214 {
1215 if (bufIsChanged(buf2)
1216 && (buf2->b_ffname != NULL
1217#ifdef FEAT_BROWSE
1218 || cmdmod.browse
1219#endif
1220 )
1221 && !buf2->b_p_ro)
1222 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001223 bufref_T bufref;
1224
1225 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001226#ifdef FEAT_BROWSE
1227 /* May get file name, when there is none */
1228 browse_save_fname(buf2);
1229#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001230 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1231 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1232 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001234
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001236 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 }
1239 }
1240 }
1241 else if (ret == VIM_DISCARDALL)
1242 {
1243 /*
1244 * mark all buffers as unchanged
1245 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001246 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +02001247 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248 }
1249}
1250#endif
1251
1252/*
1253 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1254 * hidden, autowriting it or unloading it.
1255 */
1256 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001257can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258{
Bram Moolenaareb44a682017-08-03 22:44:55 +02001259 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 || !bufIsChanged(buf)
1261 || buf->b_nwindows > 1
1262 || autowrite(buf, forceit) == OK
1263 || forceit);
1264}
1265
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001266/*
1267 * Add a buffer number to "bufnrs", unless it's already there.
1268 */
1269 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001270add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001271{
1272 int i;
1273
1274 for (i = 0; i < *bufnump; ++i)
1275 if (bufnrs[i] == nr)
1276 return;
1277 bufnrs[*bufnump] = nr;
1278 *bufnump = *bufnump + 1;
1279}
1280
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281/*
1282 * Return TRUE if any buffer was changed and cannot be abandoned.
1283 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001284 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +01001285 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286 */
1287 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001288check_changed_any(
1289 int hidden, /* Only check hidden buffers */
1290 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001292 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 buf_T *buf;
1294 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001295 int i;
1296 int bufnum = 0;
1297 int bufcount = 0;
1298 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001299 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001302 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001303 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001304 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001306 if (bufcount == 0)
1307 return FALSE;
1308
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001309 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001310 if (bufnrs == NULL)
1311 return FALSE;
1312
1313 /* curbuf */
1314 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001315
1316 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001317 FOR_ALL_WINDOWS(wp)
1318 if (wp->w_buffer != curbuf)
1319 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1320
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001321 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +02001322 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001323 if (tp != curtab)
1324 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1325 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001326
1327 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +02001328 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001329 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1330
1331 for (i = 0; i < bufnum; ++i)
1332 {
1333 buf = buflist_findnr(bufnrs[i]);
1334 if (buf == NULL)
1335 continue;
1336 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1337 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001338 bufref_T bufref;
1339
1340 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001341#ifdef FEAT_TERMINAL
1342 if (term_job_running(buf->b_term))
1343 {
1344 if (term_try_stop_job(buf) == FAIL)
1345 break;
1346 }
1347 else
1348#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001349 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02001350 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001351 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1352 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001353 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001354 break; /* didn't save - still changes */
1355 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356 }
1357
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001358 if (i >= bufnum)
1359 goto theend;
1360
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001361 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001362 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001363 exiting = FALSE;
1364#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1365 /*
1366 * When ":confirm" used, don't give an error message.
1367 */
1368 if (!(p_confirm || cmdmod.confirm))
1369#endif
1370 {
1371 /* There must be a wait_return for this message, do_buffer()
1372 * may cause a redraw. But wait_return() is a no-op when vgetc()
1373 * is busy (Quit used from window menu), then make sure we don't
1374 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001375 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001376 {
1377 msg_row = cmdline_row;
1378 msg_col = 0;
1379 msg_didout = FALSE;
1380 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001381 if (
1382#ifdef FEAT_TERMINAL
1383 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001384 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +02001385 buf->b_fname)
1386 :
1387#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001388 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001389 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390 {
1391 save = no_wait_return;
1392 no_wait_return = FALSE;
1393 wait_return(FALSE);
1394 no_wait_return = save;
1395 }
1396 }
1397
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 /* Try to find a window that contains the buffer. */
1399 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001400 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401 if (wp->w_buffer == buf)
1402 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001403 bufref_T bufref;
1404
1405 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001406
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001407 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001408
Bram Moolenaarbdace832019-03-02 10:13:42 +01001409 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001410 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001411 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001412 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001414buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001415
1416 /* Open the changed buffer in the current window. */
1417 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001418 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001420theend:
1421 vim_free(bufnrs);
1422 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001423}
1424
1425/*
1426 * return FAIL if there is no file name, OK if there is one
1427 * give error message for FAIL
1428 */
1429 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001430check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431{
1432 if (curbuf->b_ffname == NULL)
1433 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001434 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001435 return FAIL;
1436 }
1437 return OK;
1438}
1439
1440/*
1441 * flush the contents of a buffer, unless it has no file name
1442 *
1443 * return FAIL for failure, OK otherwise
1444 */
1445 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001446buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001447{
1448 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001449 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450
1451 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1452 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1453 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001454 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001455 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01001456 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01001457 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001458 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001459 return retval;
1460}
1461
1462/*
1463 * Code to handle the argument list.
1464 */
1465
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001466static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001467static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001468static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001469#define AL_SET 1
1470#define AL_ADD 2
1471#define AL_DEL 3
1472
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001474 * Isolate one argument, taking backticks.
1475 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476 * Return a pointer to the start of the next argument.
1477 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001478 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001479do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480{
1481 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482 int inbacktick;
1483
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484 inbacktick = FALSE;
1485 for (p = str; *str; ++str)
1486 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001487 /* When the backslash is used for escaping the special meaning of a
1488 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001489 if (rem_backslash(str))
1490 {
1491 *p++ = *str++;
1492 *p++ = *str;
1493 }
1494 else
1495 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001496 /* An item ends at a space not in backticks */
1497 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001499 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001501 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001502 }
1503 }
1504 str = skipwhite(str);
1505 *p = NUL;
1506
1507 return str;
1508}
1509
Bram Moolenaar86b68352004-12-27 21:59:20 +00001510/*
1511 * Separate the arguments in "str" and return a list of pointers in the
1512 * growarray "gap".
1513 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001514 static int
1515get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001516{
1517 ga_init2(gap, (int)sizeof(char_u *), 20);
1518 while (*str != NUL)
1519 {
1520 if (ga_grow(gap, 1) == FAIL)
1521 {
1522 ga_clear(gap);
1523 return FAIL;
1524 }
1525 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1526
Bram Moolenaar398ee732017-08-03 14:29:14 +02001527 /* If str is escaped, don't handle backslashes or spaces */
1528 if (!escaped)
1529 return OK;
1530
Bram Moolenaar86b68352004-12-27 21:59:20 +00001531 /* Isolate one argument, change it in-place, put a NUL after it. */
1532 str = do_one_arg(str);
1533 }
1534 return OK;
1535}
1536
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001537#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001538/*
1539 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001540 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001541 * Return FAIL or OK.
1542 */
1543 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001544get_arglist_exp(
1545 char_u *str,
1546 int *fcountp,
1547 char_u ***fnamesp,
1548 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001549{
1550 garray_T ga;
1551 int i;
1552
Bram Moolenaar398ee732017-08-03 14:29:14 +02001553 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001554 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001555 if (wig == TRUE)
1556 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1557 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1558 else
1559 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1560 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1561
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001562 ga_clear(&ga);
1563 return i;
1564}
1565#endif
1566
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567/*
1568 * Redefine the argument list.
1569 */
1570 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001571set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001572{
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001573 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575
1576/*
1577 * "what" == AL_SET: Redefine the argument list to 'str'.
1578 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1579 * "what" == AL_DEL: remove files in 'str' from the argument list.
1580 *
1581 * Return FAIL for failure, OK otherwise.
1582 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001584do_arglist(
1585 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01001586 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001587 int after UNUSED, // 0 means before first one
1588 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589{
1590 garray_T new_ga;
1591 int exp_count;
1592 char_u **exp_files;
1593 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594 char_u *p;
1595 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001596 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597
1598 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001599 * Set default argument for ":argadd" command.
1600 */
1601 if (what == AL_ADD && *str == NUL)
1602 {
1603 if (curbuf->b_ffname == NULL)
1604 return FAIL;
1605 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001606 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001607 }
1608
1609 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610 * Collect all file name arguments in "new_ga".
1611 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001612 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001613 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 if (what == AL_DEL)
1616 {
1617 regmatch_T regmatch;
1618 int didone;
1619
1620 /*
1621 * Delete the items: use each item as a regexp and find a match in the
1622 * argument list.
1623 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001624 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1626 {
1627 p = ((char_u **)new_ga.ga_data)[i];
1628 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1629 if (p == NULL)
1630 break;
1631 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1632 if (regmatch.regprog == NULL)
1633 {
1634 vim_free(p);
1635 break;
1636 }
1637
1638 didone = FALSE;
1639 for (match = 0; match < ARGCOUNT; ++match)
1640 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1641 (colnr_T)0))
1642 {
1643 didone = TRUE;
1644 vim_free(ARGLIST[match].ae_fname);
1645 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1646 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1647 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 if (curwin->w_arg_idx > match)
1649 --curwin->w_arg_idx;
1650 --match;
1651 }
1652
Bram Moolenaar473de612013-06-08 18:19:48 +02001653 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 vim_free(p);
1655 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001656 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657 }
1658 ga_clear(&new_ga);
1659 }
1660 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661 {
1662 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1663 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1664 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01001665 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001667 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001668 return FAIL;
1669 }
1670
Bram Moolenaar071d4272004-06-13 20:20:40 +00001671 if (what == AL_ADD)
1672 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001673 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 vim_free(exp_files);
1675 }
1676 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001677 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678 }
1679
1680 alist_check_arg_idx();
1681
1682 return OK;
1683}
1684
1685/*
1686 * Check the validity of the arg_idx for each other window.
1687 */
1688 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001689alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001692 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693
Bram Moolenaarf740b292006-02-16 22:11:02 +00001694 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001695 if (win->w_alist == curwin->w_alist)
1696 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697}
1698
1699/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001700 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001701 * index.
1702 */
1703 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001704editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001705{
1706 return !(win->w_arg_idx >= WARGCOUNT(win)
1707 || (win->w_buffer->b_fnum
1708 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1709 && (win->w_buffer->b_ffname == NULL
1710 || !(fullpathcmp(
1711 alist_name(&WARGLIST(win)[win->w_arg_idx]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001712 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))));
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001713}
1714
1715/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716 * Check if window "win" is editing the w_arg_idx file in its argument list.
1717 */
1718 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001719check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001721 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722 {
1723 /* We are not editing the current entry in the argument list.
1724 * Set "arg_had_last" if we are editing the last one. */
1725 win->w_arg_idx_invalid = TRUE;
1726 if (win->w_arg_idx != WARGCOUNT(win) - 1
1727 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 && GARGCOUNT > 0
1730 && win->w_arg_idx < GARGCOUNT
1731 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1732 || (win->w_buffer->b_ffname != NULL
1733 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001734 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735 arg_had_last = TRUE;
1736 }
1737 else
1738 {
1739 /* We are editing the current entry in the argument list.
1740 * Set "arg_had_last" if it's also the last one */
1741 win->w_arg_idx_invalid = FALSE;
1742 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02001743 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 arg_had_last = TRUE;
1745 }
1746}
1747
1748/*
1749 * ":args", ":argslocal" and ":argsglobal".
1750 */
1751 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001752ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753{
1754 int i;
1755
1756 if (eap->cmdidx != CMD_args)
1757 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758 alist_unlink(ALIST(curwin));
1759 if (eap->cmdidx == CMD_argglobal)
1760 ALIST(curwin) = &global_alist;
1761 else /* eap->cmdidx == CMD_arglocal */
1762 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 }
1764
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01001765 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766 {
1767 /*
1768 * ":args file ..": define new argument list, handle like ":next"
1769 * Also for ":argslocal file .." and ":argsglobal file ..".
1770 */
1771 ex_next(eap);
1772 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001773 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774 {
1775 /*
1776 * ":args": list arguments.
1777 */
1778 if (ARGCOUNT > 0)
1779 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001780 char_u **items = ALLOC_MULT(char_u *, ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001781
1782 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001784 /* Overwrite the command, for a short list there is no
1785 * scrolling required and no wait_return(). */
1786 gotocmdline(TRUE);
1787
1788 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001789 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001790 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
1791 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 }
1793 }
1794 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 else if (eap->cmdidx == CMD_arglocal)
1796 {
1797 garray_T *gap = &curwin->w_alist->al_ga;
1798
1799 /*
1800 * ":argslocal": make a local copy of the global argument list.
1801 */
1802 if (ga_grow(gap, GARGCOUNT) == OK)
1803 for (i = 0; i < GARGCOUNT; ++i)
1804 if (GARGLIST[i].ae_fname != NULL)
1805 {
1806 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1807 vim_strsave(GARGLIST[i].ae_fname);
1808 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1809 GARGLIST[i].ae_fnum;
1810 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811 }
1812 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813}
1814
1815/*
1816 * ":previous", ":sprevious", ":Next" and ":sNext".
1817 */
1818 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001819ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820{
1821 /* If past the last one already, go to the last one. */
1822 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1823 do_argfile(eap, ARGCOUNT - 1);
1824 else
1825 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1826}
1827
1828/*
1829 * ":rewind", ":first", ":sfirst" and ":srewind".
1830 */
1831 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001832ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833{
1834 do_argfile(eap, 0);
1835}
1836
1837/*
1838 * ":last" and ":slast".
1839 */
1840 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001841ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842{
1843 do_argfile(eap, ARGCOUNT - 1);
1844}
1845
1846/*
1847 * ":argument" and ":sargument".
1848 */
1849 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001850ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851{
1852 int i;
1853
1854 if (eap->addr_count > 0)
1855 i = eap->line2 - 1;
1856 else
1857 i = curwin->w_arg_idx;
1858 do_argfile(eap, i);
1859}
1860
1861/*
1862 * Edit file "argn" of the argument lists.
1863 */
1864 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001865do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866{
1867 int other;
1868 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001869 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870
Bram Moolenaar8cdbd5b2019-06-16 15:50:45 +02001871 if (ERROR_IF_POPUP_WINDOW)
Bram Moolenaar815b76b2019-06-01 14:15:52 +02001872 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 if (argn < 0 || argn >= ARGCOUNT)
1874 {
1875 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001876 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001878 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001880 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881 }
1882 else
1883 {
1884 setpcmark();
1885#ifdef FEAT_GUI
1886 need_mouse_correct = TRUE;
1887#endif
1888
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00001889 /* split window or create new tab page first */
1890 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 {
1892 if (win_split(0, 0) == FAIL)
1893 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001894 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 }
1896 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 {
1898 /*
1899 * if 'hidden' set, only check for changed file when re-editing
1900 * the same buffer
1901 */
1902 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02001903 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 {
1905 p = fix_fname(alist_name(&ARGLIST[argn]));
1906 other = otherfile(p);
1907 vim_free(p);
1908 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001909 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001910 && check_changed(curbuf, CCGD_AW
1911 | (other ? 0 : CCGD_MULTWIN)
1912 | (eap->forceit ? CCGD_FORCEIT : 0)
1913 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 return;
1915 }
1916
1917 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001918 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919 arg_had_last = TRUE;
1920
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001921 /* Edit the file; always use the last known line number.
1922 * When it fails (e.g. Abort for already edited file) restore the
1923 * argument index. */
1924 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02001926 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001927 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001928 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001930 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 setmark('\'');
1932 }
1933}
1934
1935/*
1936 * ":next", and commands that behave like it.
1937 */
1938 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001939ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940{
1941 int i;
1942
1943 /*
1944 * check for changed buffer now, if this fails the argument list is not
1945 * redefined.
1946 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02001947 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001949 || !check_changed(curbuf, CCGD_AW
1950 | (eap->forceit ? CCGD_FORCEIT : 0)
1951 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 {
1953 if (*eap->arg != NUL) /* redefine file list */
1954 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001955 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 return;
1957 i = 0;
1958 }
1959 else
1960 i = curwin->w_arg_idx + (int)eap->line2;
1961 do_argfile(eap, i);
1962 }
1963}
1964
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965/*
1966 * ":argedit"
1967 */
1968 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001969ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970{
Bram Moolenaar90305c62017-07-16 15:31:17 +02001971 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001972 // Whether curbuf will be reused, curbuf->b_ffname will be set.
1973 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001975 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02001976 return;
1977#ifdef FEAT_TITLE
1978 maketitle();
1979#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001981 if (curwin->w_arg_idx == 0
1982 && (curbuf->b_ml.ml_flags & ML_EMPTY)
1983 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02001984 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02001986 if (i < ARGCOUNT)
1987 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988}
1989
1990/*
1991 * ":argadd"
1992 */
1993 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001994ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995{
1996 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001997 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
1998 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999#ifdef FEAT_TITLE
2000 maketitle();
2001#endif
2002}
2003
2004/*
2005 * ":argdelete"
2006 */
2007 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002008ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002009{
2010 int i;
2011 int n;
2012
2013 if (eap->addr_count > 0)
2014 {
2015 /* ":1,4argdel": Delete all arguments in the range. */
2016 if (eap->line2 > ARGCOUNT)
2017 eap->line2 = ARGCOUNT;
2018 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002019 if (*eap->arg != NUL)
2020 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002021 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002022 else if (n <= 0)
2023 {
2024 /* Don't give an error for ":%argdel" if the list is empty. */
2025 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002026 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002027 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002028 else
2029 {
2030 for (i = eap->line1; i <= eap->line2; ++i)
2031 vim_free(ARGLIST[i - 1].ae_fname);
2032 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2033 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2034 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002035 if (curwin->w_arg_idx >= eap->line2)
2036 curwin->w_arg_idx -= n;
2037 else if (curwin->w_arg_idx > eap->line1)
2038 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002039 if (ARGCOUNT == 0)
2040 curwin->w_arg_idx = 0;
2041 else if (curwin->w_arg_idx >= ARGCOUNT)
2042 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 }
2044 }
2045 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002046 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002048 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049#ifdef FEAT_TITLE
2050 maketitle();
2051#endif
2052}
2053
2054/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002055 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002056 */
2057 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002058ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059{
2060 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002061 win_T *wp;
2062 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01002063 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002065#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002067#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002068 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002069#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002070 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002071 int qf_idx;
2072#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002074#ifndef FEAT_QUICKFIX
2075 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2076 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2077 {
2078 ex_ni(eap);
2079 return;
2080 }
2081#endif
2082
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002083#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002084 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002085 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2086 * great speed improvement. */
2087 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002089#ifdef FEAT_CLIPBOARD
2090 start_global_changes();
2091#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092
2093 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002094 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02002095 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002096 || !check_changed(curbuf, CCGD_AW
2097 | (eap->forceit ? CCGD_FORCEIT : 0)
2098 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002099 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002100 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002101 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002102 wp = firstwin;
2103 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002104 switch (eap->cmdidx)
2105 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01002106 case CMD_windo:
2107 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2108 i++;
2109 break;
2110 case CMD_tabdo:
2111 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2112 i++;
2113 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002114 case CMD_argdo:
2115 i = eap->line1 - 1;
2116 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002117 default:
2118 break;
2119 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120 /* set pcmark now */
2121 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002122 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002123 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002124 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002125 || !buf->b_p_bl); buf = buf->b_next)
2126 if (buf->b_fnum > eap->line2)
2127 {
2128 buf = NULL;
2129 break;
2130 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002131 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002132 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002133 }
2134#ifdef FEAT_QUICKFIX
2135 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2136 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2137 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02002138 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002139 if (qf_size <= 0 || eap->line1 > qf_size)
2140 buf = NULL;
2141 else
2142 {
2143 ex_cc(eap);
2144
2145 buf = curbuf;
2146 i = eap->line1 - 1;
2147 if (eap->addr_count <= 0)
2148 /* default is all the quickfix/location list entries */
2149 eap->line2 = qf_size;
2150 }
2151 }
2152#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002153 else
2154 setpcmark();
2155 listcmd_busy = TRUE; /* avoids setting pcmark below */
2156
Bram Moolenaare25bb902015-02-27 20:33:37 +01002157 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002158 {
2159 if (eap->cmdidx == CMD_argdo)
2160 {
2161 /* go to argument "i" */
2162 if (i == ARGCOUNT)
2163 break;
2164 /* Don't call do_argfile() when already there, it will try
2165 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002166 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002167 {
2168 /* Clear 'shm' to avoid that the file message overwrites
2169 * any output from the command. */
2170 p_shm_save = vim_strsave(p_shm);
2171 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002173 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2174 vim_free(p_shm_save);
2175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176 if (curwin->w_arg_idx != i)
2177 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002179 else if (eap->cmdidx == CMD_windo)
2180 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002181 /* go to window "wp" */
2182 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002184 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002185 if (curwin != wp)
2186 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002187 wp = curwin->w_next;
2188 }
2189 else if (eap->cmdidx == CMD_tabdo)
2190 {
2191 /* go to window "tp" */
2192 if (!valid_tabpage(tp))
2193 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002194 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002195 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002196 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 else if (eap->cmdidx == CMD_bufdo)
2198 {
2199 /* Remember the number of the next listed buffer, in case
2200 * ":bwipe" is used or autocommands do something strange. */
2201 next_fnum = -1;
2202 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2203 if (buf->b_p_bl)
2204 {
2205 next_fnum = buf->b_fnum;
2206 break;
2207 }
2208 }
2209
Bram Moolenaara162bc52015-01-07 16:54:21 +01002210 ++i;
2211
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212 /* execute the command */
2213 do_cmdline(eap->arg, eap->getline, eap->cookie,
2214 DOCMD_VERBOSE + DOCMD_NOWAIT);
2215
2216 if (eap->cmdidx == CMD_bufdo)
2217 {
2218 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002219 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220 break;
2221 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02002222 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 if (buf->b_fnum == next_fnum)
2224 break;
2225 if (buf == NULL)
2226 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002227
2228 /* Go to the next buffer. Clear 'shm' to avoid that the file
2229 * message overwrites any output from the command. */
2230 p_shm_save = vim_strsave(p_shm);
2231 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002233 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2234 vim_free(p_shm_save);
2235
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002236 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002237 if (curbuf->b_fnum != next_fnum)
2238 break;
2239 }
2240
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002241#ifdef FEAT_QUICKFIX
2242 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2243 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2244 {
2245 if (i >= qf_size || i >= eap->line2)
2246 break;
2247
2248 qf_idx = qf_get_cur_idx(eap);
2249
2250 ex_cnext(eap);
2251
2252 /* If jumping to the next quickfix entry fails, quit here */
2253 if (qf_get_cur_idx(eap) == qf_idx)
2254 break;
2255 }
2256#endif
2257
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 if (eap->cmdidx == CMD_windo)
2259 {
2260 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01002261
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 /* required when 'scrollbind' has been set */
2263 if (curwin->w_p_scb)
2264 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002266
Bram Moolenaara162bc52015-01-07 16:54:21 +01002267 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2268 if (i+1 > eap->line2)
2269 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002270 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2271 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002272 }
2273 listcmd_busy = FALSE;
2274 }
2275
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002276#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002277 if (save_ei != NULL)
2278 {
2279 au_event_restore(save_ei);
2280 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2281 curbuf->b_fname, TRUE, curbuf);
2282 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002284#ifdef FEAT_CLIPBOARD
2285 end_global_changes();
2286#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287}
2288
2289/*
2290 * Add files[count] to the arglist of the current window after arg "after".
2291 * The file names in files[count] must have been allocated and are taken over.
2292 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002294 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002295alist_add_list(
2296 int count,
2297 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002298 int after, // where to add: 0 = before first one
2299 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300{
2301 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002302 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303
2304 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2305 {
2306 if (after < 0)
2307 after = 0;
2308 if (after > ARGCOUNT)
2309 after = ARGCOUNT;
2310 if (after < ARGCOUNT)
2311 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2312 (ARGCOUNT - after) * sizeof(aentry_T));
2313 for (i = 0; i < count; ++i)
2314 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002315 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
2316
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002318 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 }
2320 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002321 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2322 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002323 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324 }
2325
2326 for (i = 0; i < count; ++i)
2327 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328}
2329
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02002330#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2331/*
2332 * Function given to ExpandGeneric() to obtain the possible arguments of the
2333 * argedit and argdelete commands.
2334 */
2335 char_u *
2336get_arglist_name(expand_T *xp UNUSED, int idx)
2337{
2338 if (idx >= ARGCOUNT)
2339 return NULL;
2340
2341 return alist_name(&ARGLIST[idx]);
2342}
2343#endif
2344
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02002345
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346#ifdef FEAT_EVAL
2347/*
2348 * ":compiler[!] {name}"
2349 */
2350 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002351ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352{
2353 char_u *buf;
2354 char_u *old_cur_comp = NULL;
2355 char_u *p;
2356
2357 if (*eap->arg == NUL)
2358 {
2359 /* List all compiler scripts. */
2360 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2361 /* ) keep the indenter happy... */
2362 }
2363 else
2364 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02002365 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 if (buf != NULL)
2367 {
2368 if (eap->forceit)
2369 {
2370 /* ":compiler! {name}" sets global options */
2371 do_cmdline_cmd((char_u *)
2372 "command -nargs=* CompilerSet set <args>");
2373 }
2374 else
2375 {
2376 /* ":compiler! {name}" sets local options.
2377 * To remain backwards compatible "current_compiler" is always
2378 * used. A user's compiler plugin may set it, the distributed
2379 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002380 * "b:current_compiler" and restore "current_compiler".
2381 * Explicitly prepend "g:" to make it work in a function. */
2382 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 if (old_cur_comp != NULL)
2384 old_cur_comp = vim_strsave(old_cur_comp);
2385 do_cmdline_cmd((char_u *)
2386 "command -nargs=* CompilerSet setlocal <args>");
2387 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002388 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002389 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390
2391 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002392 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002393 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 vim_free(buf);
2395
2396 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2397
2398 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002399 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400 if (p != NULL)
2401 set_internal_string_var((char_u *)"b:current_compiler", p);
2402
2403 /* Restore "current_compiler" for ":compiler {name}". */
2404 if (!eap->forceit)
2405 {
2406 if (old_cur_comp != NULL)
2407 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002408 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 old_cur_comp);
2410 vim_free(old_cur_comp);
2411 }
2412 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002413 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 }
2415 }
2416 }
2417}
2418#endif
2419
2420/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002421 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422 */
2423 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002424ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002426 char_u *arg = eap->arg;
2427 char_u *p = skiptowhite(arg);
2428 int len = (int)(p - arg);
2429 int flags = eap->forceit ? DIP_ALL : 0;
2430
2431 if (STRNCMP(arg, "START", len) == 0)
2432 {
2433 flags += DIP_START + DIP_NORTP;
2434 arg = skipwhite(arg + len);
2435 }
2436 else if (STRNCMP(arg, "OPT", len) == 0)
2437 {
2438 flags += DIP_OPT + DIP_NORTP;
2439 arg = skipwhite(arg + len);
2440 }
2441 else if (STRNCMP(arg, "PACK", len) == 0)
2442 {
2443 flags += DIP_START + DIP_OPT + DIP_NORTP;
2444 arg = skipwhite(arg + len);
2445 }
2446 else if (STRNCMP(arg, "ALL", len) == 0)
2447 {
2448 flags += DIP_START + DIP_OPT;
2449 arg = skipwhite(arg + len);
2450 }
2451
2452 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453}
2454
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002456source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002458 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459}
2460
2461/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002462 * Find the file "name" in all directories in "path" and invoke
2463 * "callback(fname, cookie)".
2464 * "name" can contain wildcards.
2465 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2466 * When "flags" has DIP_DIR: find directories instead of files.
2467 * When "flags" has DIP_ERR: give an error message if there is no match.
2468 *
2469 * return FAIL when no file could be sourced, OK otherwise.
2470 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01002471 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002472do_in_path(
2473 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002474 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01002475 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002476 void (*callback)(char_u *fname, void *ck),
2477 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478{
2479 char_u *rtp;
2480 char_u *np;
2481 char_u *buf;
2482 char_u *rtp_copy;
2483 char_u *tail;
2484 int num_files;
2485 char_u **files;
2486 int i;
2487 int did_one = FALSE;
2488#ifdef AMIGA
2489 struct Process *proc = (struct Process *)FindTask(0L);
2490 APTR save_winptr = proc->pr_WindowPtr;
2491
2492 /* Avoid a requester here for a volume that doesn't exist. */
2493 proc->pr_WindowPtr = (APTR)-1L;
2494#endif
2495
2496 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2497 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002498 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 buf = alloc(MAXPATHL);
2500 if (buf != NULL && rtp_copy != NULL)
2501 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002502 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002503 {
2504 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002505 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002506 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002507 verbose_leave();
2508 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002509
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510 /* Loop over all entries in 'runtimepath'. */
2511 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01002512 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02002514 size_t buflen;
2515
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 /* Copy the path from 'runtimepath' to buf[]. */
2517 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02002518 buflen = STRLEN(buf);
2519
2520 /* Skip after or non-after directories. */
2521 if (flags & (DIP_NOAFTER | DIP_AFTER))
2522 {
2523 int is_after = buflen >= 5
2524 && STRCMP(buf + buflen - 5, "after") == 0;
2525
2526 if ((is_after && (flags & DIP_NOAFTER))
2527 || (!is_after && (flags & DIP_AFTER)))
2528 continue;
2529 }
2530
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002531 if (name == NULL)
2532 {
2533 (*callback)(buf, (void *) &cookie);
2534 if (!did_one)
2535 did_one = (cookie == NULL);
2536 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02002537 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538 {
2539 add_pathsep(buf);
2540 tail = buf + STRLEN(buf);
2541
2542 /* Loop over all patterns in "name" */
2543 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01002544 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545 {
2546 /* Append the pattern from "name" to buf[]. */
2547 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2548 "\t ");
2549
2550 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002551 {
2552 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002553 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002554 verbose_leave();
2555 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556
2557 /* Expand wildcards, invoke the callback for each match. */
2558 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01002559 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 {
2561 for (i = 0; i < num_files; ++i)
2562 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002563 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01002565 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 break;
2567 }
2568 FreeWild(num_files, files);
2569 }
2570 }
2571 }
2572 }
2573 }
2574 vim_free(buf);
2575 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002576 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002577 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002578 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
2579
2580 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002581 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002582 else if (p_verbose > 0)
2583 {
2584 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002585 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002586 verbose_leave();
2587 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002588 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589
2590#ifdef AMIGA
2591 proc->pr_WindowPtr = save_winptr;
2592#endif
2593
2594 return did_one ? OK : FAIL;
2595}
2596
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002597/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002598 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002599 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002600 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
2601 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002602 * Returns OK when at least one match found, FAIL otherwise.
2603 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002604 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002605 * passed by reference in this case, setting it to NULL indicates that callback
2606 * has done its job.
2607 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002608 static int
2609do_in_path_and_pp(
2610 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002611 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002612 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002613 void (*callback)(char_u *fname, void *ck),
2614 void *cookie)
2615{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002616 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002617 char_u *s;
2618 int len;
2619 char *start_dir = "pack/*/start/*/%s";
2620 char *opt_dir = "pack/*/opt/*/%s";
2621
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002622 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002623 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002624
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002625 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002626 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002627 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002628 s = alloc(len);
2629 if (s == NULL)
2630 return FAIL;
2631 vim_snprintf((char *)s, len, start_dir, name);
2632 done = do_in_path(p_pp, s, flags, callback, cookie);
2633 vim_free(s);
2634 }
2635
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002636 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002637 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002638 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002639 s = alloc(len);
2640 if (s == NULL)
2641 return FAIL;
2642 vim_snprintf((char *)s, len, opt_dir, name);
2643 done = do_in_path(p_pp, s, flags, callback, cookie);
2644 vim_free(s);
2645 }
2646
2647 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002648}
2649
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002650/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002651 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2652 */
2653 int
2654do_in_runtimepath(
2655 char_u *name,
2656 int flags,
2657 void (*callback)(char_u *fname, void *ck),
2658 void *cookie)
2659{
2660 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2661}
2662
2663/*
2664 * Source the file "name" from all directories in 'runtimepath'.
2665 * "name" can contain wildcards.
2666 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2667 *
2668 * return FAIL when no file could be sourced, OK otherwise.
2669 */
2670 int
2671source_runtime(char_u *name, int flags)
2672{
2673 return source_in_path(p_rtp, name, flags);
2674}
2675
2676/*
2677 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2678 */
2679 int
2680source_in_path(char_u *path, char_u *name, int flags)
2681{
2682 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2683}
2684
2685
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002686#if defined(FEAT_EVAL) || defined(PROTO)
2687
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002688/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002689 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002690 */
2691 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002692source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002693{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002694 int num_files;
2695 char_u **files;
2696 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002697
Bram Moolenaarf3654822016-03-04 22:12:23 +01002698 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002699 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002700 for (i = 0; i < num_files; ++i)
2701 (void)do_source(files[i], FALSE, DOSO_NONE);
2702 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002703 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002704}
2705
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002706/*
2707 * Add the package directory to 'runtimepath'.
2708 */
2709 static int
2710add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002711{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002712 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002713 char_u *entry;
2714 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002715 int c;
2716 char_u *new_rtp;
2717 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002718 size_t oldlen;
2719 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002720 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002721 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002722 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002723 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002724 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002725 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002726 char_u *buf = NULL;
2727 char_u *rtp_ffname;
2728 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002729 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002730
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002731 p4 = p3 = p2 = p1 = get_past_head(fname);
2732 for (p = p1; *p; MB_PTR_ADV(p))
2733 if (vim_ispathsep_nocolon(*p))
2734 {
2735 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2736 }
2737
2738 /* now we have:
2739 * rtp/pack/name/start/name
2740 * p4 p3 p2 p1
2741 *
2742 * find the part up to "pack" in 'runtimepath' */
2743 c = *++p4; /* append pathsep in order to expand symlink */
2744 *p4 = NUL;
2745 ffname = fix_fname(fname);
2746 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002747 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002748 return FAIL;
2749
Bram Moolenaar99396d42018-09-08 18:21:16 +02002750 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2751 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002752 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002753 buf = alloc(MAXPATHL);
2754 if (buf == NULL)
2755 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002756 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002757 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002758 char_u *cur_entry = entry;
2759
2760 copy_option_part(&entry, buf, MAXPATHL, ",");
2761 if (insp == NULL)
2762 {
2763 add_pathsep(buf);
2764 rtp_ffname = fix_fname(buf);
2765 if (rtp_ffname == NULL)
2766 goto theend;
2767 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2768 vim_free(rtp_ffname);
2769 if (match)
2770 // Insert "ffname" after this entry (and comma).
2771 insp = entry;
2772 }
2773
2774 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2775 && p > buf
2776 && vim_ispathsep(p[-1])
2777 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2778 {
2779 if (insp == NULL)
2780 // Did not find "ffname" before the first "after" directory,
2781 // insert it before this entry.
2782 insp = cur_entry;
2783 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002784 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002785 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002786 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002787
Bram Moolenaar99396d42018-09-08 18:21:16 +02002788 if (insp == NULL)
2789 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002790 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002791
Bram Moolenaar99396d42018-09-08 18:21:16 +02002792 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002793 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2794 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002795 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002796
2797 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002798 addlen = STRLEN(fname) + 1; // add one for comma
Bram Moolenaar51e14382019-05-25 20:21:28 +02002799 new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002800 if (new_rtp == NULL)
2801 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002802
2803 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2804 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002805 keep = (int)(insp - p_rtp);
2806 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002807 new_rtp_len = keep;
2808 if (*insp == NUL)
2809 new_rtp[new_rtp_len++] = ','; // add comma before
2810 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2811 new_rtp_len += addlen - 1;
2812 if (*insp != NUL)
2813 new_rtp[new_rtp_len++] = ','; // add comma after
2814
2815 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002816 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002817 int keep_after = (int)(after_insp - p_rtp);
2818
2819 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2820 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2821 keep_after - keep);
2822 new_rtp_len += keep_after - keep;
2823 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2824 new_rtp_len += afterlen - 1;
2825 new_rtp[new_rtp_len++] = ',';
2826 keep = keep_after;
2827 }
2828
2829 if (p_rtp[keep] != NUL)
2830 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2831 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2832 else
2833 new_rtp[new_rtp_len] = NUL;
2834
2835 if (afterlen > 0 && after_insp == NULL)
2836 {
2837 // Append afterdir when "after" was not found:
2838 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002839 STRCAT(new_rtp, ",");
2840 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002841 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002842
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002843 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2844 vim_free(new_rtp);
2845 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002846
2847theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002848 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002849 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002850 vim_free(afterdir);
2851 return retval;
2852}
2853
2854/*
2855 * Load scripts in "plugin" and "ftdetect" directories of the package.
2856 */
2857 static int
2858load_pack_plugin(char_u *fname)
2859{
2860 static char *plugpat = "%s/plugin/**/*.vim";
2861 static char *ftpat = "%s/ftdetect/*.vim";
2862 int len;
2863 char_u *ffname = fix_fname(fname);
2864 char_u *pat = NULL;
2865 int retval = FAIL;
2866
2867 if (ffname == NULL)
2868 return FAIL;
2869 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2870 pat = alloc(len);
2871 if (pat == NULL)
2872 goto theend;
2873 vim_snprintf((char *)pat, len, plugpat, ffname);
2874 source_all_matches(pat);
2875
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002876 {
2877 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2878
2879 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2880 * found when it loads. */
2881 if (cmd != NULL && eval_to_number(cmd) > 0)
2882 {
2883 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2884 vim_snprintf((char *)pat, len, ftpat, ffname);
2885 source_all_matches(pat);
2886 do_cmdline_cmd((char_u *)"augroup END");
2887 }
2888 vim_free(cmd);
2889 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002890 vim_free(pat);
2891 retval = OK;
2892
2893theend:
2894 vim_free(ffname);
2895 return retval;
2896}
2897
2898/* used for "cookie" of add_pack_plugin() */
2899static int APP_ADD_DIR;
2900static int APP_LOAD;
2901static int APP_BOTH;
2902
2903 static void
2904add_pack_plugin(char_u *fname, void *cookie)
2905{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002906 if (cookie != &APP_LOAD)
2907 {
2908 char_u *buf = alloc(MAXPATHL);
2909 char_u *p;
2910 int found = FALSE;
2911
2912 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002913 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002914 p = p_rtp;
2915 while (*p != NUL)
2916 {
2917 copy_option_part(&p, buf, MAXPATHL, ",");
2918 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2919 {
2920 found = TRUE;
2921 break;
2922 }
2923 }
2924 vim_free(buf);
2925 if (!found)
2926 /* directory is not yet in 'runtimepath', add it */
2927 if (add_pack_dir_to_rtp(fname) == FAIL)
2928 return;
2929 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002930
2931 if (cookie != &APP_ADD_DIR)
2932 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002933}
2934
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002935/*
2936 * Add all packages in the "start" directory to 'runtimepath'.
2937 */
2938 void
2939add_pack_start_dirs(void)
2940{
2941 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2942 add_pack_plugin, &APP_ADD_DIR);
2943}
2944
2945/*
2946 * Load plugins from all packages in the "start" directory.
2947 */
2948 void
2949load_start_packages(void)
2950{
2951 did_source_packages = TRUE;
2952 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2953 add_pack_plugin, &APP_LOAD);
2954}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002955
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002956/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002957 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002958 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002959 */
2960 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002961ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002962{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002963 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002964 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002965 /* First do a round to add all directories to 'runtimepath', then load
2966 * the plugins. This allows for plugins to use an autoload directory
2967 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002968 add_pack_start_dirs();
2969 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002970 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002971}
2972
2973/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002974 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002975 */
2976 void
2977ex_packadd(exarg_T *eap)
2978{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002979 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002980 int len;
2981 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002982 int round;
2983 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002984
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002985 /* Round 1: use "start", round 2: use "opt". */
2986 for (round = 1; round <= 2; ++round)
2987 {
2988 /* Only look under "start" when loading packages wasn't done yet. */
2989 if (round == 1 && did_source_packages)
2990 continue;
2991
2992 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002993 pat = alloc(len);
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002994 if (pat == NULL)
2995 return;
2996 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
2997 /* The first round don't give a "not found" error, in the second round
2998 * only when nothing was found in the first round. */
2999 res = do_in_path(p_pp, (char_u *)pat,
3000 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
3001 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
3002 vim_free(pat);
3003 }
Bram Moolenaar91715872016-03-03 17:13:03 +01003004}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003005#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01003006
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003007#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008/*
3009 * ":options"
3010 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003012ex_options(
3013 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014{
Bram Moolenaare0b59492019-05-21 20:54:45 +02003015 vim_setenv((char_u *)"OPTWIN_CMD",
3016 (char_u *)(cmdmod.tab ? "tab"
3017 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3019}
3020#endif
3021
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003022#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3023
3024# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3025/*
3026 * Detect Python 3 or 2, and initialize 'pyxversion'.
3027 */
3028 void
3029init_pyxversion(void)
3030{
3031 if (p_pyx == 0)
3032 {
3033 if (python3_enabled(FALSE))
3034 p_pyx = 3;
3035 else if (python_enabled(FALSE))
3036 p_pyx = 2;
3037 }
3038}
3039# endif
3040
3041/*
3042 * Does a file contain one of the following strings at the beginning of any
3043 * line?
3044 * "#!(any string)python2" => returns 2
3045 * "#!(any string)python3" => returns 3
3046 * "# requires python 2.x" => returns 2
3047 * "# requires python 3.x" => returns 3
3048 * otherwise return 0.
3049 */
3050 static int
3051requires_py_version(char_u *filename)
3052{
3053 FILE *file;
3054 int requires_py_version = 0;
3055 int i, lines;
3056
3057 lines = (int)p_mls;
3058 if (lines < 0)
3059 lines = 5;
3060
3061 file = mch_fopen((char *)filename, "r");
3062 if (file != NULL)
3063 {
3064 for (i = 0; i < lines; i++)
3065 {
3066 if (vim_fgets(IObuff, IOSIZE, file))
3067 break;
3068 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3069 {
3070 /* Check shebang. */
3071 if (strstr((char *)IObuff + 2, "python2") != NULL)
3072 {
3073 requires_py_version = 2;
3074 break;
3075 }
3076 if (strstr((char *)IObuff + 2, "python3") != NULL)
3077 {
3078 requires_py_version = 3;
3079 break;
3080 }
3081 }
3082 IObuff[21] = '\0';
3083 if (STRCMP("# requires python 2.x", IObuff) == 0)
3084 {
3085 requires_py_version = 2;
3086 break;
3087 }
3088 if (STRCMP("# requires python 3.x", IObuff) == 0)
3089 {
3090 requires_py_version = 3;
3091 break;
3092 }
3093 }
3094 fclose(file);
3095 }
3096 return requires_py_version;
3097}
3098
3099
3100/*
3101 * Source a python file using the requested python version.
3102 */
3103 static void
3104source_pyx_file(exarg_T *eap, char_u *fname)
3105{
3106 exarg_T ex;
3107 int v = requires_py_version(fname);
3108
3109# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3110 init_pyxversion();
3111# endif
3112 if (v == 0)
3113 {
3114# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3115 /* user didn't choose a preference, 'pyx' is used */
3116 v = p_pyx;
3117# elif defined(FEAT_PYTHON)
3118 v = 2;
3119# elif defined(FEAT_PYTHON3)
3120 v = 3;
3121# endif
3122 }
3123
3124 /*
3125 * now source, if required python version is not supported show
3126 * unobtrusive message.
3127 */
3128 if (eap == NULL)
3129 vim_memset(&ex, 0, sizeof(ex));
3130 else
3131 ex = *eap;
3132 ex.arg = fname;
3133 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3134
3135 if (v == 2)
3136 {
3137# ifdef FEAT_PYTHON
3138 ex_pyfile(&ex);
3139# else
3140 vim_snprintf((char *)IObuff, IOSIZE,
3141 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3142 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003143 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003144# endif
3145 return;
3146 }
3147 else
3148 {
3149# ifdef FEAT_PYTHON3
3150 ex_py3file(&ex);
3151# else
3152 vim_snprintf((char *)IObuff, IOSIZE,
3153 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3154 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003155 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003156# endif
3157 return;
3158 }
3159}
3160
3161/*
3162 * ":pyxfile {fname}"
3163 */
3164 void
3165ex_pyxfile(exarg_T *eap)
3166{
3167 source_pyx_file(eap, eap->arg);
3168}
3169
3170/*
3171 * ":pyx"
3172 */
3173 void
3174ex_pyx(exarg_T *eap)
3175{
3176# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3177 init_pyxversion();
3178 if (p_pyx == 2)
3179 ex_python(eap);
3180 else
3181 ex_py3(eap);
3182# elif defined(FEAT_PYTHON)
3183 ex_python(eap);
3184# elif defined(FEAT_PYTHON3)
3185 ex_py3(eap);
3186# endif
3187}
3188
3189/*
3190 * ":pyxdo"
3191 */
3192 void
3193ex_pyxdo(exarg_T *eap)
3194{
3195# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3196 init_pyxversion();
3197 if (p_pyx == 2)
3198 ex_pydo(eap);
3199 else
3200 ex_py3do(eap);
3201# elif defined(FEAT_PYTHON)
3202 ex_pydo(eap);
3203# elif defined(FEAT_PYTHON3)
3204 ex_py3do(eap);
3205# endif
3206}
3207
3208#endif
3209
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210/*
3211 * ":source {fname}"
3212 */
3213 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003214ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215{
3216#ifdef FEAT_BROWSE
3217 if (cmdmod.browse)
3218 {
3219 char_u *fname = NULL;
3220
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003221 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02003222 NULL, NULL,
3223 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224 if (fname != NULL)
3225 {
3226 cmd_source(fname, eap);
3227 vim_free(fname);
3228 }
3229 }
3230 else
3231#endif
3232 cmd_source(eap->arg, eap);
3233}
3234
3235 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003236cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237{
3238 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003239 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003242 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003243 * Need to execute the commands directly. This is required at least
3244 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245 * - ":g" command busy
3246 * - after ":argdo", ":windo" or ":bufdo"
3247 * - another command follows
3248 * - inside a loop
3249 */
3250 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3251#ifdef FEAT_EVAL
3252 || eap->cstack->cs_idx >= 0
3253#endif
3254 );
3255
3256 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003257 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003258 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003259}
3260
3261/*
3262 * ":source" and associated commands.
3263 */
3264/*
3265 * Structure used to store info for each sourced file.
3266 * It is shared between do_source() and getsourceline().
3267 * This is required, because it needs to be handed to do_cmdline() and
3268 * sourcing can be done recursively.
3269 */
3270struct source_cookie
3271{
3272 FILE *fp; /* opened file for sourcing */
3273 char_u *nextline; /* if not NULL: line that was read ahead */
3274 int finished; /* ":finish" used */
Bram Moolenaar00590742019-02-15 21:06:09 +01003275#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3277 int error; /* TRUE if LF found after CR-LF */
3278#endif
3279#ifdef FEAT_EVAL
3280 linenr_T breakpoint; /* next line with breakpoint or zero */
3281 char_u *fname; /* name of sourced file */
3282 int dbg_tick; /* debug_tick when breakpoint was set */
3283 int level; /* top nesting level of sourced file */
3284#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285 vimconv_T conv; /* type of conversion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286};
3287
3288#ifdef FEAT_EVAL
3289/*
3290 * Return the address holding the next breakpoint line for a source cookie.
3291 */
3292 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003293source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294{
3295 return &((struct source_cookie *)cookie)->breakpoint;
3296}
3297
3298/*
3299 * Return the address holding the debug tick for a source cookie.
3300 */
3301 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003302source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303{
3304 return &((struct source_cookie *)cookie)->dbg_tick;
3305}
3306
3307/*
3308 * Return the nesting level for a source cookie.
3309 */
3310 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003311source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312{
3313 return ((struct source_cookie *)cookie)->level;
3314}
3315#endif
3316
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003317static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318
Bram Moolenaar4f974752019-02-17 17:44:42 +01003319#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003320# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321/*
3322 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003323 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 */
3325 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003326fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003328# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003329 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3330# else
3331 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003332# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333
3334 if (fd_tmp == -1)
3335 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003336
3337# ifdef HAVE_FD_CLOEXEC
3338 {
3339 int fdflags = fcntl(fd_tmp, F_GETFD);
3340 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003341 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003342 }
3343# endif
3344
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 return fdopen(fd_tmp, READBIN);
3346}
3347#endif
3348
3349
3350/*
3351 * do_source: Read the file "fname" and execute its lines as EX commands.
3352 *
3353 * This function may be called recursively!
3354 *
3355 * return FAIL if file could not be opened, OK otherwise
3356 */
3357 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003358do_source(
3359 char_u *fname,
3360 int check_other, /* check for .vimrc and _vimrc */
3361 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362{
3363 struct source_cookie cookie;
3364 char_u *save_sourcing_name;
3365 linenr_T save_sourcing_lnum;
3366 char_u *p;
3367 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003368 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003369 int retval = FAIL;
3370#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003371 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003373 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003374 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003376 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003378 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379 int stat_ok;
3380# endif
3381#endif
3382#ifdef STARTUPTIME
3383 struct timeval tv_rel;
3384 struct timeval tv_start;
3385#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003386#ifdef FEAT_PROFILE
3387 proftime_T wait_start;
3388#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003389 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003390
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 if (p == NULL)
3393 return retval;
3394 fname_exp = fix_fname(p);
3395 vim_free(p);
3396 if (fname_exp == NULL)
3397 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003398 if (mch_isdir(fname_exp))
3399 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003400 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003401 goto theend;
3402 }
3403
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003404 /* Apply SourceCmd autocommands, they should get the file and source it. */
3405 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3406 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3407 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003408 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003409#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003410 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003411#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003412 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003413#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003414 if (retval == OK)
3415 // Apply SourcePost autocommands.
3416 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
3417 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003418 goto theend;
3419 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003420
3421 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003422 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003423
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003424#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3426#else
3427 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3428#endif
3429 if (cookie.fp == NULL && check_other)
3430 {
3431 /*
3432 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3433 * and ".exrc" by "_exrc" or vice versa.
3434 */
3435 p = gettail(fname_exp);
3436 if ((*p == '.' || *p == '_')
3437 && (STRICMP(p + 1, "vimrc") == 0
3438 || STRICMP(p + 1, "gvimrc") == 0
3439 || STRICMP(p + 1, "exrc") == 0))
3440 {
3441 if (*p == '_')
3442 *p = '.';
3443 else
3444 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003445#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3447#else
3448 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3449#endif
3450 }
3451 }
3452
3453 if (cookie.fp == NULL)
3454 {
3455 if (p_verbose > 0)
3456 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003457 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003459 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003461 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003462 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003463 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 }
3465 goto theend;
3466 }
3467
3468 /*
3469 * The file exists.
3470 * - In verbose mode, give a message.
3471 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3472 */
3473 if (p_verbose > 1)
3474 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003475 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003477 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003479 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003480 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003481 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003483 if (is_vimrc == DOSO_VIMRC)
3484 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3485 else if (is_vimrc == DOSO_GVIMRC)
3486 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487
3488#ifdef USE_CRNL
3489 /* If no automatic file format: Set default to CR-NL. */
3490 if (*p_ffs == NUL)
3491 cookie.fileformat = EOL_DOS;
3492 else
3493 cookie.fileformat = EOL_UNKNOWN;
3494 cookie.error = FALSE;
3495#endif
3496
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497 cookie.nextline = NULL;
3498 cookie.finished = FALSE;
3499
3500#ifdef FEAT_EVAL
3501 /*
3502 * Check if this script has a breakpoint.
3503 */
3504 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3505 cookie.fname = fname_exp;
3506 cookie.dbg_tick = debug_tick;
3507
3508 cookie.level = ex_nesting_level;
3509#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510
3511 /*
3512 * Keep the sourcing name/lnum, for recursive calls.
3513 */
3514 save_sourcing_name = sourcing_name;
3515 sourcing_name = fname_exp;
3516 save_sourcing_lnum = sourcing_lnum;
3517 sourcing_lnum = 0;
3518
3519#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003520 if (time_fd != NULL)
3521 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522#endif
3523
3524#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003525# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003526 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003527 prof_child_enter(&wait_start); /* entering a child now */
3528# endif
3529
3530 /* Don't use local function variables, if called from a function.
3531 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003532 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003533
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003534 save_current_sctx = current_sctx;
3535 current_sctx.sc_lnum = 0;
3536 current_sctx.sc_version = 1;
3537
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003538 // Check if this script was sourced before to finds its SID.
3539 // If it's new, generate a new SID.
3540 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003541 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542# ifdef UNIX
3543 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3544# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003545 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
3546 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003547 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003548 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003549 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003550 && (
3551# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003552 /* Compare dev/ino when possible, it catches symbolic
3553 * links. Also compare file names, the inode may change
3554 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003555 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003556 && (si->sn_dev == st.st_dev
3557 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003558# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003559 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003561 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003562 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003563 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003564 current_sctx.sc_sid = ++last_current_SID;
3565 if (ga_grow(&script_items,
3566 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003567 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003568 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003570 ++script_items.ga_len;
3571 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3572# ifdef FEAT_PROFILE
3573 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003574# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003576 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003577 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01003578 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00003579# ifdef UNIX
3580 if (stat_ok)
3581 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003582 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003583 si->sn_dev = st.st_dev;
3584 si->sn_ino = st.st_ino;
3585 }
3586 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003587 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003588# endif
3589
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003591 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592 }
3593
Bram Moolenaar05159a02005-02-26 23:04:13 +00003594# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003595 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003596 {
3597 int forceit;
3598
3599 /* Check if we do profiling for this script. */
3600 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3601 {
3602 script_do_profile(si);
3603 si->sn_pr_force = forceit;
3604 }
3605 if (si->sn_prof_on)
3606 {
3607 ++si->sn_pr_count;
3608 profile_start(&si->sn_pr_start);
3609 profile_zero(&si->sn_pr_children);
3610 }
3611 }
3612# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613#endif
3614
Bram Moolenaar67435d92017-10-19 21:04:37 +02003615 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3616
3617 /* Read the first line so we can check for a UTF-8 BOM. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02003618 firstline = getsourceline(0, (void *)&cookie, 0, TRUE);
Bram Moolenaar67435d92017-10-19 21:04:37 +02003619 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3620 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3621 {
3622 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3623 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3624 p = string_convert(&cookie.conv, firstline + 3, NULL);
3625 if (p == NULL)
3626 p = vim_strsave(firstline + 3);
3627 if (p != NULL)
3628 {
3629 vim_free(firstline);
3630 firstline = p;
3631 }
3632 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02003633
Bram Moolenaar071d4272004-06-13 20:20:40 +00003634 /*
3635 * Call do_cmdline, which will call getsourceline() to get the lines.
3636 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003637 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003640
3641#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003642 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003643 {
3644 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003645 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003646 if (si->sn_prof_on)
3647 {
3648 profile_end(&si->sn_pr_start);
3649 profile_sub_wait(&wait_start, &si->sn_pr_start);
3650 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003651 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3652 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003653 }
3654 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655#endif
3656
3657 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003658 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 sourcing_name = save_sourcing_name;
3660 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 if (p_verbose > 1)
3662 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003663 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003664 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003666 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003667 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668 }
3669#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003670 if (time_fd != NULL)
3671 {
3672 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3673 time_msg((char *)IObuff, &tv_start);
3674 time_pop(&tv_rel);
3675 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676#endif
3677
Bram Moolenaar2b618522019-01-12 13:26:03 +01003678 if (!got_int)
3679 trigger_source_post = TRUE;
3680
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681#ifdef FEAT_EVAL
3682 /*
3683 * After a "finish" in debug mode, need to break at first command of next
3684 * sourced file.
3685 */
3686 if (save_debug_break_level > ex_nesting_level
3687 && debug_break_level == ex_nesting_level)
3688 ++debug_break_level;
3689#endif
3690
Bram Moolenaar05159a02005-02-26 23:04:13 +00003691#ifdef FEAT_EVAL
3692almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003693 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003694 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003695# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003696 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003697 prof_child_exit(&wait_start); /* leaving a child now */
3698# endif
3699#endif
3700 fclose(cookie.fp);
3701 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003702 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003703 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003704
Bram Moolenaar2b618522019-01-12 13:26:03 +01003705 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003706 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003707
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708theend:
3709 vim_free(fname_exp);
3710 return retval;
3711}
3712
3713#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003714
Bram Moolenaar071d4272004-06-13 20:20:40 +00003715/*
3716 * ":scriptnames"
3717 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003719ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720{
3721 int i;
3722
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003723 if (eap->addr_count > 0)
3724 {
3725 // :script {scriptId}: edit the script
3726 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003727 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003728 else
3729 {
3730 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3731 do_exedit(eap, NULL);
3732 }
3733 return;
3734 }
3735
Bram Moolenaar05159a02005-02-26 23:04:13 +00003736 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3737 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003738 {
3739 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3740 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003741 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003742 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743}
3744
3745# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3746/*
3747 * Fix slashes in the list of script names for 'shellslash'.
3748 */
3749 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003750scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751{
3752 int i;
3753
Bram Moolenaar05159a02005-02-26 23:04:13 +00003754 for (i = 1; i <= script_items.ga_len; ++i)
3755 if (SCRIPT_ITEM(i).sn_name != NULL)
3756 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757}
3758# endif
3759
3760/*
3761 * Get a pointer to a script name. Used for ":verbose set".
3762 */
3763 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003764get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765{
3766 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003767 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003768 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003769 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003770 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003771 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003773 return (char_u *)_("environment variable");
3774 if (id == SID_ERROR)
3775 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003776 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003778
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003779# if defined(EXITFREE) || defined(PROTO)
3780 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003781free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003782{
3783 int i;
3784
3785 for (i = script_items.ga_len; i > 0; --i)
3786 vim_free(SCRIPT_ITEM(i).sn_name);
3787 ga_clear(&script_items);
3788}
3789# endif
3790
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791#endif
3792
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793/*
3794 * Get one full line from a sourced file.
3795 * Called by do_cmdline() when it's called from do_source().
3796 *
3797 * Return a pointer to the line in allocated memory.
3798 * Return NULL for end-of-file or some error.
3799 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800 char_u *
Bram Moolenaare96a2492019-06-25 04:12:16 +02003801getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802{
3803 struct source_cookie *sp = (struct source_cookie *)cookie;
3804 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003805 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806
3807#ifdef FEAT_EVAL
3808 /* If breakpoints have been added/deleted need to check for it. */
3809 if (sp->dbg_tick < debug_tick)
3810 {
3811 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3812 sp->dbg_tick = debug_tick;
3813 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003814# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003815 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003816 script_line_end();
3817# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818#endif
3819 /*
3820 * Get current line. If there is a read-ahead line, use it, otherwise get
3821 * one now.
3822 */
3823 if (sp->finished)
3824 line = NULL;
3825 else if (sp->nextline == NULL)
3826 line = get_one_sourceline(sp);
3827 else
3828 {
3829 line = sp->nextline;
3830 sp->nextline = NULL;
3831 ++sourcing_lnum;
3832 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003833#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003834 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003835 script_line_start();
3836#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837
3838 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3839 * contain the 'C' flag. */
Bram Moolenaare96a2492019-06-25 04:12:16 +02003840 if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841 {
3842 /* compensate for the one line read-ahead */
3843 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003844
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003845 // Get the next line and concatenate it when it starts with a
3846 // backslash. We always need to read the next line, keep it in
3847 // sp->nextline.
3848 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003849 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003850 if (sp->nextline != NULL
3851 && (*(p = skipwhite(sp->nextline)) == '\\'
3852 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003853 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003854 garray_T ga;
3855
Bram Moolenaarb549a732012-02-22 18:29:33 +01003856 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003857 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003858 if (*p == '\\')
3859 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003860 for (;;)
3861 {
3862 vim_free(sp->nextline);
3863 sp->nextline = get_one_sourceline(sp);
3864 if (sp->nextline == NULL)
3865 break;
3866 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003867 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003868 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003869 // Adjust the growsize to the current length to speed up
3870 // concatenating many lines.
3871 if (ga.ga_len > 400)
3872 {
3873 if (ga.ga_len > 8000)
3874 ga.ga_growsize = 8000;
3875 else
3876 ga.ga_growsize = ga.ga_len;
3877 }
3878 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003879 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003880 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3881 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003882 }
3883 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003885 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886 }
3887 }
3888
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3890 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003891 char_u *s;
3892
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 /* Convert the encoding of the script line. */
3894 s = string_convert(&sp->conv, line, NULL);
3895 if (s != NULL)
3896 {
3897 vim_free(line);
3898 line = s;
3899 }
3900 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901
3902#ifdef FEAT_EVAL
3903 /* Did we encounter a breakpoint? */
3904 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3905 {
3906 dbg_breakpoint(sp->fname, sourcing_lnum);
3907 /* Find next breakpoint. */
3908 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3909 sp->dbg_tick = debug_tick;
3910 }
3911#endif
3912
3913 return line;
3914}
3915
3916 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003917get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003918{
3919 garray_T ga;
3920 int len;
3921 int c;
3922 char_u *buf;
3923#ifdef USE_CRNL
3924 int has_cr; /* CR-LF found */
3925#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926 int have_read = FALSE;
3927
3928 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003929 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930
3931 /*
3932 * Loop until there is a finished line (or end-of-file).
3933 */
3934 sourcing_lnum++;
3935 for (;;)
3936 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003937 /* make room to read at least 120 (more) characters */
3938 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003939 break;
3940 buf = (char_u *)ga.ga_data;
3941
Bram Moolenaar00590742019-02-15 21:06:09 +01003942 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003943 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003944 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003945 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946#ifdef USE_CRNL
3947 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3948 * CTRL-Z by its own, or after a NL. */
3949 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3950 && sp->fileformat == EOL_DOS
3951 && buf[len - 1] == Ctrl_Z)
3952 {
3953 buf[len - 1] = NUL;
3954 break;
3955 }
3956#endif
3957
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959 ga.ga_len = len;
3960
3961 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003962 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 continue;
3964
3965 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3966 {
3967#ifdef USE_CRNL
3968 has_cr = (len >= 2 && buf[len - 2] == '\r');
3969 if (sp->fileformat == EOL_UNKNOWN)
3970 {
3971 if (has_cr)
3972 sp->fileformat = EOL_DOS;
3973 else
3974 sp->fileformat = EOL_UNIX;
3975 }
3976
3977 if (sp->fileformat == EOL_DOS)
3978 {
3979 if (has_cr) /* replace trailing CR */
3980 {
3981 buf[len - 2] = '\n';
3982 --len;
3983 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984 }
3985 else /* lines like ":map xx yy^M" will have failed */
3986 {
3987 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003988 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003989 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003990 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003991 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992 sp->error = TRUE;
3993 sp->fileformat = EOL_UNIX;
3994 }
3995 }
3996#endif
3997 /* The '\n' is escaped if there is an odd number of ^V's just
3998 * before it, first set "c" just before the 'V's and then check
3999 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4000 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4001 ;
4002 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4003 {
4004 sourcing_lnum++;
4005 continue;
4006 }
4007
4008 buf[len - 1] = NUL; /* remove the NL */
4009 }
4010
4011 /*
4012 * Check for ^C here now and then, so recursive :so can be broken.
4013 */
4014 line_breakcheck();
4015 break;
4016 }
4017
4018 if (have_read)
4019 return (char_u *)ga.ga_data;
4020
4021 vim_free(ga.ga_data);
4022 return NULL;
4023}
4024
Bram Moolenaar05159a02005-02-26 23:04:13 +00004025#if defined(FEAT_PROFILE) || defined(PROTO)
4026/*
4027 * Called when starting to read a script line.
4028 * "sourcing_lnum" must be correct!
4029 * When skipping lines it may not actually be executed, but we won't find out
4030 * until later and we need to store the time now.
4031 */
4032 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004033script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004034{
4035 scriptitem_T *si;
4036 sn_prl_T *pp;
4037
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004038 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004039 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004040 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004041 if (si->sn_prof_on && sourcing_lnum >= 1)
4042 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004043 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004044 * here isn't counted. */
Bram Moolenaar67435d92017-10-19 21:04:37 +02004045 (void)ga_grow(&si->sn_prl_ga,
4046 (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004047 si->sn_prl_idx = sourcing_lnum - 1;
4048 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4049 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4050 {
4051 /* Zero counters for a line that was not used before. */
4052 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4053 pp->snp_count = 0;
4054 profile_zero(&pp->sn_prl_total);
4055 profile_zero(&pp->sn_prl_self);
4056 ++si->sn_prl_ga.ga_len;
4057 }
4058 si->sn_prl_execed = FALSE;
4059 profile_start(&si->sn_prl_start);
4060 profile_zero(&si->sn_prl_children);
4061 profile_get_wait(&si->sn_prl_wait);
4062 }
4063}
4064
4065/*
4066 * Called when actually executing a function line.
4067 */
4068 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004069script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004070{
4071 scriptitem_T *si;
4072
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004073 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004074 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004075 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004076 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4077 si->sn_prl_execed = TRUE;
4078}
4079
4080/*
Bram Moolenaar67435d92017-10-19 21:04:37 +02004081 * Called when done with a script line.
Bram Moolenaar05159a02005-02-26 23:04:13 +00004082 */
4083 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004084script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004085{
4086 scriptitem_T *si;
4087 sn_prl_T *pp;
4088
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004089 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004090 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004091 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004092 if (si->sn_prof_on && si->sn_prl_idx >= 0
4093 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4094 {
4095 if (si->sn_prl_execed)
4096 {
4097 pp = &PRL_ITEM(si, si->sn_prl_idx);
4098 ++pp->snp_count;
4099 profile_end(&si->sn_prl_start);
4100 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004101 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004102 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4103 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004104 }
4105 si->sn_prl_idx = -1;
4106 }
4107}
4108#endif
4109
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110/*
4111 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004114ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116 struct source_cookie *sp;
4117 char_u *name;
4118
4119 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4120 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004121 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 return;
4123 }
4124
4125 if (*eap->arg != NUL)
4126 {
4127 name = enc_canonize(eap->arg);
4128 if (name == NULL) /* out of memory */
4129 return;
4130 }
4131 else
4132 name = eap->arg;
4133
4134 /* Setup for conversion from the specified encoding to 'encoding'. */
4135 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4136 convert_setup(&sp->conv, name, p_enc);
4137
4138 if (name != eap->arg)
4139 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140}
4141
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004142/*
4143 * ":scriptversion": Set Vim script version for a sourced script.
4144 */
4145 void
4146ex_scriptversion(exarg_T *eap UNUSED)
4147{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004148#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004149 int nr;
4150
4151 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4152 {
4153 emsg(_("E984: :scriptversion used outside of a sourced file"));
4154 return;
4155 }
4156
4157 nr = getdigits(&eap->arg);
4158 if (nr == 0 || *eap->arg != NUL)
4159 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02004160 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004161 semsg(_("E999: scriptversion not supported: %d"), nr);
4162 else
4163 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004164#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004165}
4166
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167#if defined(FEAT_EVAL) || defined(PROTO)
4168/*
4169 * ":finish": Mark a sourced file as finished.
4170 */
4171 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004172ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173{
4174 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4175 do_finish(eap, FALSE);
4176 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004177 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178}
4179
4180/*
4181 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4182 * Also called for a pending finish at the ":endtry" or after returning from
4183 * an extra do_cmdline(). "reanimate" is used in the latter case.
4184 */
4185 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004186do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187{
4188 int idx;
4189
4190 if (reanimate)
4191 ((struct source_cookie *)getline_cookie(eap->getline,
4192 eap->cookie))->finished = FALSE;
4193
4194 /*
4195 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4196 * not in its finally clause (which then is to be executed next) is found.
4197 * In this case, make the ":finish" pending for execution at the ":endtry".
4198 * Otherwise, finish normally.
4199 */
4200 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4201 if (idx >= 0)
4202 {
4203 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4204 report_make_pending(CSTP_FINISH, NULL);
4205 }
4206 else
4207 ((struct source_cookie *)getline_cookie(eap->getline,
4208 eap->cookie))->finished = TRUE;
4209}
4210
4211
4212/*
4213 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4214 * message for missing ":endif".
4215 * Return FALSE when not sourcing a file.
4216 */
4217 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004218source_finished(
Bram Moolenaare96a2492019-06-25 04:12:16 +02004219 char_u *(*fgetline)(int, void *, int, int),
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004220 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004222 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004224 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225}
4226#endif
4227
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228/*
4229 * ":checktime [buffer]"
4230 */
4231 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004232ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233{
4234 buf_T *buf;
4235 int save_no_check_timestamps = no_check_timestamps;
4236
4237 no_check_timestamps = 0;
4238 if (eap->addr_count == 0) /* default is all buffers */
4239 check_timestamps(FALSE);
4240 else
4241 {
4242 buf = buflist_findnr((int)eap->line2);
4243 if (buf != NULL) /* cannot happen? */
4244 (void)buf_check_timestamp(buf, FALSE);
4245 }
4246 no_check_timestamps = save_no_check_timestamps;
4247}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248
Bram Moolenaar071d4272004-06-13 20:20:40 +00004249#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4250 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004251# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004252 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004253get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004255 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004257 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004258 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004259
Bram Moolenaar4f974752019-02-17 17:44:42 +01004260# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 if (loc != NULL)
4262 {
4263 char_u *p;
4264
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004265 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4266 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 p = vim_strchr(loc, '=');
4268 if (p != NULL)
4269 {
4270 loc = ++p;
4271 while (*p != NUL) /* remove trailing newline */
4272 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004273 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274 {
4275 *p = NUL;
4276 break;
4277 }
4278 ++p;
4279 }
4280 }
4281 }
4282# endif
4283
4284 return loc;
4285}
4286#endif
4287
4288
Bram Moolenaar4f974752019-02-17 17:44:42 +01004289#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290/*
4291 * On MS-Windows locale names are strings like "German_Germany.1252", but
4292 * gettext expects "de". Try to translate one into another here for a few
4293 * supported languages.
4294 */
4295 static char_u *
4296gettext_lang(char_u *name)
4297{
4298 int i;
4299 static char *(mtable[]) = {
4300 "afrikaans", "af",
4301 "czech", "cs",
4302 "dutch", "nl",
4303 "german", "de",
4304 "english_united kingdom", "en_GB",
4305 "spanish", "es",
4306 "french", "fr",
4307 "italian", "it",
4308 "japanese", "ja",
4309 "korean", "ko",
4310 "norwegian", "no",
4311 "polish", "pl",
4312 "russian", "ru",
4313 "slovak", "sk",
4314 "swedish", "sv",
4315 "ukrainian", "uk",
4316 "chinese_china", "zh_CN",
4317 "chinese_taiwan", "zh_TW",
4318 NULL};
4319
4320 for (i = 0; mtable[i] != NULL; i += 2)
4321 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004322 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 return name;
4324}
4325#endif
4326
4327#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4328/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01004329 * Return TRUE when "lang" starts with a valid language name.
4330 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
4331 */
4332 static int
4333is_valid_mess_lang(char_u *lang)
4334{
4335 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
4336}
4337
4338/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004339 * Obtain the current messages language. Used to set the default for
4340 * 'helplang'. May return NULL or an empty string.
4341 */
4342 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004343get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344{
4345 char_u *p;
4346
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004347# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004349 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350# else
4351 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004352 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4353 * and LC_MONETARY may be set differently for a Japanese working in the
4354 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004355 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356# endif
4357# else
4358 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004359 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360 {
4361 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004362 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 p = mch_getenv((char_u *)"LANG");
4364 }
4365# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004366# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 p = gettext_lang(p);
4368# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01004369 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370}
4371#endif
4372
Bram Moolenaardef9e822004-12-31 20:58:58 +00004373/* Complicated #if; matches with where get_mess_env() is used below. */
4374#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4375 && defined(LC_MESSAGES))) \
4376 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00004377 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378/*
4379 * Get the language used for messages from the environment.
4380 */
4381 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004382get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004383{
4384 char_u *p;
4385
4386 p = mch_getenv((char_u *)"LC_ALL");
4387 if (p == NULL || *p == NUL)
4388 {
4389 p = mch_getenv((char_u *)"LC_MESSAGES");
4390 if (p == NULL || *p == NUL)
4391 {
4392 p = mch_getenv((char_u *)"LANG");
4393 if (p != NULL && VIM_ISDIGIT(*p))
4394 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004395# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004397 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398# endif
4399 }
4400 }
4401 return p;
4402}
4403#endif
4404
4405#if defined(FEAT_EVAL) || defined(PROTO)
4406
4407/*
4408 * Set the "v:lang" variable according to the current locale setting.
4409 * Also do "v:lc_time"and "v:ctype".
4410 */
4411 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004412set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413{
4414 char_u *loc;
4415
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004416# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004417 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418# else
4419 /* setlocale() not supported: use the default value */
4420 loc = (char_u *)"C";
4421# endif
4422 set_vim_var_string(VV_CTYPE, loc, -1);
4423
4424 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4425 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004426# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004427 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004428# else
4429 loc = get_mess_env();
4430# endif
4431 set_vim_var_string(VV_LANG, loc, -1);
4432
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004433# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004434 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435# endif
4436 set_vim_var_string(VV_LC_TIME, loc, -1);
4437}
4438#endif
4439
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01004440#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441/*
4442 * ":language": Set the language (locale).
4443 */
4444 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004445ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446{
4447 char *loc;
4448 char_u *p;
4449 char_u *name;
4450 int what = LC_ALL;
4451 char *whatstr = "";
4452#ifdef LC_MESSAGES
4453# define VIM_LC_MESSAGES LC_MESSAGES
4454#else
4455# define VIM_LC_MESSAGES 6789
4456#endif
4457
4458 name = eap->arg;
4459
4460 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4461 * Allow abbreviation, but require at least 3 characters to avoid
4462 * confusion with a two letter language name "me" or "ct". */
4463 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004464 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465 {
4466 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4467 {
4468 what = VIM_LC_MESSAGES;
4469 name = skipwhite(p);
4470 whatstr = "messages ";
4471 }
4472 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4473 {
4474 what = LC_CTYPE;
4475 name = skipwhite(p);
4476 whatstr = "ctype ";
4477 }
4478 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4479 {
4480 what = LC_TIME;
4481 name = skipwhite(p);
4482 whatstr = "time ";
4483 }
4484 }
4485
4486 if (*name == NUL)
4487 {
4488#ifndef LC_MESSAGES
4489 if (what == VIM_LC_MESSAGES)
4490 p = get_mess_env();
4491 else
4492#endif
4493 p = (char_u *)setlocale(what, NULL);
4494 if (p == NULL || *p == NUL)
4495 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004496 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497 }
4498 else
4499 {
4500#ifndef LC_MESSAGES
4501 if (what == VIM_LC_MESSAGES)
4502 loc = "";
4503 else
4504#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004505 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004507#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4508 /* Make sure strtod() uses a decimal point, not a comma. */
4509 setlocale(LC_NUMERIC, "C");
4510#endif
4511 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004512 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004513 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514 else
4515 {
4516#ifdef HAVE_NL_MSG_CAT_CNTR
4517 /* Need to do this for GNU gettext, otherwise cached translations
4518 * will be used again. */
4519 extern int _nl_msg_cat_cntr;
4520
4521 ++_nl_msg_cat_cntr;
4522#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004523 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004524 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4525
4526 if (what != LC_TIME)
4527 {
4528 /* Tell gettext() what to translate to. It apparently doesn't
4529 * use the currently effective locale. Also do this when
4530 * FEAT_GETTEXT isn't defined, so that shell commands use this
4531 * value. */
4532 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004533 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004535
4536 /* Clear $LANGUAGE because GNU gettext uses it. */
4537 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01004538# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004539 /* Apparently MS-Windows printf() may cause a crash when
4540 * we give it 8-bit text while it's expecting text in the
4541 * current locale. This call avoids that. */
4542 setlocale(LC_CTYPE, "C");
4543# endif
4544 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545 if (what != LC_CTYPE)
4546 {
4547 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01004548#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 mname = gettext_lang(name);
4550#else
4551 mname = name;
4552#endif
4553 vim_setenv((char_u *)"LC_MESSAGES", mname);
4554#ifdef FEAT_MULTI_LANG
4555 set_helplang_default(mname);
4556#endif
4557 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 }
4559
4560# ifdef FEAT_EVAL
4561 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4562 set_lang_var();
4563# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004564# ifdef FEAT_TITLE
4565 maketitle();
4566# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004567 }
4568 }
4569}
4570
4571# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004572
4573static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004574
Bram Moolenaar4f974752019-02-17 17:44:42 +01004575# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004576static int did_init_locales = FALSE;
4577
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004578/* Return an array of strings for all available locales + NULL for the
4579 * last element. Return NULL in case of error. */
4580 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004581find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004582{
4583 garray_T locales_ga;
4584 char_u *loc;
4585
4586 /* Find all available locales by running command "locale -a". If this
4587 * doesn't work we won't have completion. */
4588 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004589 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004590 if (locale_a == NULL)
4591 return NULL;
4592 ga_init2(&locales_ga, sizeof(char_u *), 20);
4593
4594 /* Transform locale_a string where each locale is separated by "\n"
4595 * into an array of locale strings. */
4596 loc = (char_u *)strtok((char *)locale_a, "\n");
4597
4598 while (loc != NULL)
4599 {
4600 if (ga_grow(&locales_ga, 1) == FAIL)
4601 break;
4602 loc = vim_strsave(loc);
4603 if (loc == NULL)
4604 break;
4605
4606 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4607 loc = (char_u *)strtok(NULL, "\n");
4608 }
4609 vim_free(locale_a);
4610 if (ga_grow(&locales_ga, 1) == FAIL)
4611 {
4612 ga_clear(&locales_ga);
4613 return NULL;
4614 }
4615 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4616 return (char_u **)locales_ga.ga_data;
4617}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004618# endif
4619
4620/*
4621 * Lazy initialization of all available locales.
4622 */
4623 static void
4624init_locales(void)
4625{
Bram Moolenaar4f974752019-02-17 17:44:42 +01004626# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004627 if (!did_init_locales)
4628 {
4629 did_init_locales = TRUE;
4630 locales = find_locales();
4631 }
4632# endif
4633}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004634
4635# if defined(EXITFREE) || defined(PROTO)
4636 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004637free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004638{
4639 int i;
4640 if (locales != NULL)
4641 {
4642 for (i = 0; locales[i] != NULL; i++)
4643 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004644 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004645 }
4646}
4647# endif
4648
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649/*
4650 * Function given to ExpandGeneric() to obtain the possible arguments of the
4651 * ":language" command.
4652 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004654get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655{
4656 if (idx == 0)
4657 return (char_u *)"messages";
4658 if (idx == 1)
4659 return (char_u *)"ctype";
4660 if (idx == 2)
4661 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004662
4663 init_locales();
4664 if (locales == NULL)
4665 return NULL;
4666 return locales[idx - 3];
4667}
4668
4669/*
4670 * Function given to ExpandGeneric() to obtain the available locales.
4671 */
4672 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004673get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004674{
4675 init_locales();
4676 if (locales == NULL)
4677 return NULL;
4678 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679}
4680# endif
4681
4682#endif