blob: 1e9d18e833509fc65947bf712d7747d966f8df8c [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 Moolenaar75537a92016-09-05 22:45:28 +0200285 free_callback(timer->tr_callback, timer->tr_partial);
286 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{
296 timer_T *timer = (timer_T *)alloc_clear(sizeof(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
328 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +0200329 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +0100330 timer->tr_partial, NULL);
331 clear_tv(&rettv);
332}
333
334/*
335 * Call timers that are due.
336 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200337 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100338 */
339 long
Bram Moolenaarcf089462016-06-12 21:18:43 +0200340check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100341{
342 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200343 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100344 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +0100345 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100346 proftime_T now;
347 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200348 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200349 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100350
Bram Moolenaarc577d812017-07-08 22:37:34 +0200351 /* Don't run any timers while exiting or dealing with an error. */
352 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200353 return next_due;
354
Bram Moolenaar75537a92016-09-05 22:45:28 +0200355 profile_start(&now);
356 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100357 {
Bram Moolenaar75537a92016-09-05 22:45:28 +0200358 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200359
Bram Moolenaar75537a92016-09-05 22:45:28 +0200360 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
361 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100362 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200363 if (this_due <= 1)
364 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200365 /* Save and restore a lot of flags, because the timer fires while
366 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200367 int save_timer_busy = timer_busy;
368 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200369 int save_did_emsg = did_emsg;
370 int save_called_emsg = called_emsg;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200371 int save_must_redraw = must_redraw;
Bram Moolenaare723c422017-09-06 23:40:10 +0200372 int save_trylevel = trylevel;
373 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200374 int save_ex_pressedreturn = get_pressedreturn();
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 Moolenaarb0f42ba2018-05-12 15:38:26 +0200389 save_vimvars(&vvsave);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200390 timer->tr_firing = TRUE;
391 timer_callback(timer);
392 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200393
Bram Moolenaar75537a92016-09-05 22:45:28 +0200394 timer_next = timer->tr_next;
395 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200396 timer_busy = save_timer_busy;
397 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200398 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200399 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200400 did_emsg = save_did_emsg;
401 called_emsg = save_called_emsg;
402 trylevel = save_trylevel;
403 did_throw = save_did_throw;
404 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200405 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200406 if (must_redraw != 0)
407 need_update_screen = TRUE;
408 must_redraw = must_redraw > save_must_redraw
409 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200410 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200411
412 /* Only fire the timer again if it repeats and stop_timer() wasn't
413 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200414 if (timer->tr_repeat != 0 && timer->tr_id != -1
415 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200416 {
417 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100418 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200419 if (this_due < 1)
420 this_due = 1;
421 if (timer->tr_repeat > 0)
422 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100423 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200424 else
425 {
426 this_due = -1;
427 remove_timer(timer);
428 free_timer(timer);
429 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100430 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200431 if (this_due > 0 && (next_due == -1 || next_due > this_due))
432 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100433 }
434
435 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200436 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100437
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100438#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100439 if (bevalexpr_due_set)
440 {
441 this_due = proftime_time_left(&bevalexpr_due, &now);
442 if (this_due <= 1)
443 {
444 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100445 if (balloonEval == NULL)
446 {
Bram Moolenaarca4b6132018-06-28 12:05:11 +0200447 balloonEval = (BalloonEval *)alloc_clear(sizeof(BalloonEval));
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100448 balloonEvalForTerm = TRUE;
449 }
450 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200451 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100452 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200453 setcursor();
454 out_flush();
455 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100456 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200457 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100458 next_due = this_due;
459 }
460#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200461#ifdef FEAT_TERMINAL
462 /* Some terminal windows may need their buffer updated. */
463 next_due = term_check_timers(next_due, &now);
464#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100465
Bram Moolenaar75537a92016-09-05 22:45:28 +0200466 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100467}
468
469/*
470 * Find a timer by ID. Returns NULL if not found;
471 */
472 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200473find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100474{
475 timer_T *timer;
476
Bram Moolenaar75537a92016-09-05 22:45:28 +0200477 if (id >= 0)
478 {
479 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
480 if (timer->tr_id == id)
481 return timer;
482 }
483 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100484}
485
486
487/*
488 * Stop a timer and delete it.
489 */
490 void
491stop_timer(timer_T *timer)
492{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200493 if (timer->tr_firing)
494 /* Free the timer after the callback returns. */
495 timer->tr_id = -1;
496 else
497 {
498 remove_timer(timer);
499 free_timer(timer);
500 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100501}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200502
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200503 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200504stop_all_timers(void)
505{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200506 timer_T *timer;
507 timer_T *timer_next;
508
509 for (timer = first_timer; timer != NULL; timer = timer_next)
510 {
511 timer_next = timer->tr_next;
512 stop_timer(timer);
513 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200514}
515
516 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200517add_timer_info(typval_T *rettv, timer_T *timer)
518{
519 list_T *list = rettv->vval.v_list;
520 dict_T *dict = dict_alloc();
521 dictitem_T *di;
522 long remaining;
523 proftime_T now;
524
525 if (dict == NULL)
526 return;
527 list_append_dict(list, dict);
528
Bram Moolenaare0be1672018-07-08 16:50:37 +0200529 dict_add_number(dict, "id", timer->tr_id);
530 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200531
532 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100533 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200534 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200535
Bram Moolenaare0be1672018-07-08 16:50:37 +0200536 dict_add_number(dict, "repeat",
537 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
538 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200539
540 di = dictitem_alloc((char_u *)"callback");
541 if (di != NULL)
542 {
543 if (dict_add(dict, di) == FAIL)
544 vim_free(di);
545 else if (timer->tr_partial != NULL)
546 {
547 di->di_tv.v_type = VAR_PARTIAL;
548 di->di_tv.vval.v_partial = timer->tr_partial;
549 ++timer->tr_partial->pt_refcount;
550 }
551 else
552 {
553 di->di_tv.v_type = VAR_FUNC;
554 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
555 }
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200556 }
557}
558
559 void
560add_timer_info_all(typval_T *rettv)
561{
562 timer_T *timer;
563
564 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200565 if (timer->tr_id != -1)
566 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200567}
568
Bram Moolenaare3188e22016-05-31 21:13:04 +0200569/*
570 * Mark references in partials of timers.
571 */
572 int
573set_ref_in_timer(int copyID)
574{
575 int abort = FALSE;
576 timer_T *timer;
577 typval_T tv;
578
579 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
580 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200581 if (timer->tr_partial != NULL)
582 {
583 tv.v_type = VAR_PARTIAL;
584 tv.vval.v_partial = timer->tr_partial;
585 }
586 else
587 {
588 tv.v_type = VAR_FUNC;
589 tv.vval.v_string = timer->tr_callback;
590 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200591 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
592 }
593 return abort;
594}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200595
596# if defined(EXITFREE) || defined(PROTO)
597 void
598timer_free_all()
599{
600 timer_T *timer;
601
602 while (first_timer != NULL)
603 {
604 timer = first_timer;
605 remove_timer(timer);
606 free_timer(timer);
607 }
608}
609# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100610# endif
611
Bram Moolenaar113e1072019-01-20 15:30:40 +0100612#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) && defined(FEAT_PROFILE)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200613# if defined(HAVE_MATH_H)
614# include <math.h>
615# endif
616
617/*
618 * Divide the time "tm" by "count" and store in "tm2".
619 */
620 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100621profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200622{
623 if (count == 0)
624 profile_zero(tm2);
625 else
626 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100627# ifdef MSWIN
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200628 tm2->QuadPart = tm->QuadPart / count;
629# else
630 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
631
632 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200633 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200634# endif
635 }
636}
637#endif
638
Bram Moolenaar76929292008-01-06 19:07:36 +0000639# if defined(FEAT_PROFILE) || defined(PROTO)
640/*
641 * Functions for profiling.
642 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100643static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +0000644static proftime_T prof_wait_time;
645
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000646/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000647 * Add the time "tm2" to "tm".
648 */
649 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100650profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000651{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100652# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000653 tm->QuadPart += tm2->QuadPart;
654# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000655 tm->tv_usec += tm2->tv_usec;
656 tm->tv_sec += tm2->tv_sec;
657 if (tm->tv_usec >= 1000000)
658 {
659 tm->tv_usec -= 1000000;
660 ++tm->tv_sec;
661 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000662# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000663}
664
665/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000666 * Add the "self" time from the total time and the children's time.
667 */
668 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100669profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +0000670{
671 /* Check that the result won't be negative. Can happen with recursive
672 * calls. */
Bram Moolenaar4f974752019-02-17 17:44:42 +0100673#ifdef MSWIN
Bram Moolenaar1056d982006-03-09 22:37:52 +0000674 if (total->QuadPart <= children->QuadPart)
675 return;
676#else
677 if (total->tv_sec < children->tv_sec
678 || (total->tv_sec == children->tv_sec
679 && total->tv_usec <= children->tv_usec))
680 return;
681#endif
682 profile_add(self, total);
683 profile_sub(self, children);
684}
685
686/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000687 * Get the current waittime.
688 */
689 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100690profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000691{
692 *tm = prof_wait_time;
693}
694
695/*
696 * Subtract the passed waittime since "tm" from "tma".
697 */
698 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100699profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000700{
701 proftime_T tm3 = prof_wait_time;
702
703 profile_sub(&tm3, tm);
704 profile_sub(tma, &tm3);
705}
706
707/*
708 * Return TRUE if "tm1" and "tm2" are equal.
709 */
710 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100711profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000712{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100713# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000714 return (tm1->QuadPart == tm2->QuadPart);
715# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000716 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000717# endif
718}
719
720/*
721 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
722 */
723 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100724profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000725{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100726# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000727 return (int)(tm2->QuadPart - tm1->QuadPart);
728# else
729 if (tm1->tv_sec == tm2->tv_sec)
730 return tm2->tv_usec - tm1->tv_usec;
731 return tm2->tv_sec - tm1->tv_sec;
732# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000733}
734
Bram Moolenaar05159a02005-02-26 23:04:13 +0000735static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000736static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000737
738/*
739 * ":profile cmd args"
740 */
741 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100742ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000743{
744 char_u *e;
745 int len;
746
747 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000748 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000749 e = skipwhite(e);
750
751 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
752 {
753 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +0200754 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000755 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000756 profile_zero(&prof_wait_time);
757 set_vim_var_nr(VV_PROFILING, 1L);
758 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000759 else if (do_profiling == PROF_NONE)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100760 emsg(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000761 else if (STRCMP(eap->arg, "pause") == 0)
762 {
763 if (do_profiling == PROF_YES)
764 profile_start(&pause_time);
765 do_profiling = PROF_PAUSED;
766 }
767 else if (STRCMP(eap->arg, "continue") == 0)
768 {
769 if (do_profiling == PROF_PAUSED)
770 {
771 profile_end(&pause_time);
772 profile_add(&prof_wait_time, &pause_time);
773 }
774 do_profiling = PROF_YES;
775 }
Bram Moolenaar05159a02005-02-26 23:04:13 +0000776 else
777 {
778 /* The rest is similar to ":breakadd". */
779 ex_breakadd(eap);
780 }
781}
782
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100783/* Command line expansion for :profile. */
784static enum
785{
786 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +0100787 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100788} pexpand_what;
789
790static char *pexpand_cmds[] = {
791 "start",
792#define PROFCMD_START 0
793 "pause",
794#define PROFCMD_PAUSE 1
795 "continue",
796#define PROFCMD_CONTINUE 2
797 "func",
798#define PROFCMD_FUNC 3
799 "file",
800#define PROFCMD_FILE 4
801 NULL
802#define PROFCMD_LAST 5
803};
804
805/*
806 * Function given to ExpandGeneric() to obtain the profile command
807 * specific expansion.
808 */
809 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100810get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100811{
812 switch (pexpand_what)
813 {
814 case PEXP_SUBCMD:
815 return (char_u *)pexpand_cmds[idx];
816 /* case PEXP_FUNC: TODO */
817 default:
818 return NULL;
819 }
820}
821
822/*
823 * Handle command line completion for :profile command.
824 */
825 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100826set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100827{
828 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100829
830 /* Default: expand subcommands. */
831 xp->xp_context = EXPAND_PROFILE;
832 pexpand_what = PEXP_SUBCMD;
833 xp->xp_pattern = arg;
834
835 end_subcmd = skiptowhite(arg);
836 if (*end_subcmd == NUL)
837 return;
838
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +0100839 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100840 {
841 xp->xp_context = EXPAND_FILES;
842 xp->xp_pattern = skipwhite(end_subcmd);
843 return;
844 }
845
846 /* TODO: expand function names after "func" */
847 xp->xp_context = EXPAND_NOTHING;
848}
849
Bram Moolenaar05159a02005-02-26 23:04:13 +0000850/*
851 * Dump the profiling info.
852 */
853 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100854profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000855{
856 FILE *fd;
857
858 if (profile_fname != NULL)
859 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000860 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861 if (fd == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100862 semsg(_(e_notopen), profile_fname);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000863 else
864 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000865 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000866 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000867 fclose(fd);
868 }
869 }
870}
871
872/*
873 * Start profiling script "fp".
874 */
875 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100876script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000877{
878 si->sn_pr_count = 0;
879 profile_zero(&si->sn_pr_total);
880 profile_zero(&si->sn_pr_self);
881
882 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
883 si->sn_prl_idx = -1;
884 si->sn_prof_on = TRUE;
885 si->sn_pr_nest = 0;
886}
887
888/*
Bram Moolenaar67435d92017-10-19 21:04:37 +0200889 * Save time when starting to invoke another script or function.
Bram Moolenaar05159a02005-02-26 23:04:13 +0000890 */
891 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100892script_prof_save(
893 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000894{
895 scriptitem_T *si;
896
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200897 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000898 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200899 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000900 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
901 profile_start(&si->sn_pr_child);
902 }
903 profile_get_wait(tm);
904}
905
906/*
907 * Count time spent in children after invoking another script or function.
908 */
909 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100910script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000911{
912 scriptitem_T *si;
913
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200914 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000915 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200916 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000917 if (si->sn_prof_on && --si->sn_pr_nest == 0)
918 {
919 profile_end(&si->sn_pr_child);
920 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
921 profile_add(&si->sn_pr_children, &si->sn_pr_child);
922 profile_add(&si->sn_prl_children, &si->sn_pr_child);
923 }
924 }
925}
926
927static proftime_T inchar_time;
928
929/*
930 * Called when starting to wait for the user to type a character.
931 */
932 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100933prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000934{
935 profile_start(&inchar_time);
936}
937
938/*
939 * Called when finished waiting for the user to type a character.
940 */
941 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100942prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943{
944 profile_end(&inchar_time);
945 profile_add(&prof_wait_time, &inchar_time);
946}
947
948/*
949 * Dump the profiling results for all scripts in file "fd".
950 */
951 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100952script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000953{
954 int id;
955 scriptitem_T *si;
956 int i;
957 FILE *sfd;
958 sn_prl_T *pp;
959
960 for (id = 1; id <= script_items.ga_len; ++id)
961 {
962 si = &SCRIPT_ITEM(id);
963 if (si->sn_prof_on)
964 {
965 fprintf(fd, "SCRIPT %s\n", si->sn_name);
966 if (si->sn_pr_count == 1)
967 fprintf(fd, "Sourced 1 time\n");
968 else
969 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
970 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
971 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
972 fprintf(fd, "\n");
973 fprintf(fd, "count total (s) self (s)\n");
974
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000975 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 if (sfd == NULL)
977 fprintf(fd, "Cannot open file!\n");
978 else
979 {
Bram Moolenaar67435d92017-10-19 21:04:37 +0200980 /* Keep going till the end of file, so that trailing
981 * continuation lines are listed. */
982 for (i = 0; ; ++i)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000983 {
984 if (vim_fgets(IObuff, IOSIZE, sfd))
985 break;
Bram Moolenaarac112f02017-12-05 16:46:28 +0100986 /* When a line has been truncated, append NL, taking care
987 * of multi-byte characters . */
988 if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
989 {
990 int n = IOSIZE - 2;
Bram Moolenaar13505972019-01-24 15:04:48 +0100991
Bram Moolenaarac112f02017-12-05 16:46:28 +0100992 if (enc_utf8)
993 {
994 /* Move to the first byte of this char.
995 * utf_head_off() doesn't work, because it checks
996 * for a truncated character. */
997 while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
998 --n;
999 }
1000 else if (has_mbyte)
1001 n -= mb_head_off(IObuff, IObuff + n);
Bram Moolenaarac112f02017-12-05 16:46:28 +01001002 IObuff[n] = NL;
1003 IObuff[n + 1] = NUL;
1004 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02001005 if (i < si->sn_prl_ga.ga_len
1006 && (pp = &PRL_ITEM(si, i))->snp_count > 0)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001007 {
1008 fprintf(fd, "%5d ", pp->snp_count);
1009 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1010 fprintf(fd, " ");
1011 else
1012 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1013 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1014 }
1015 else
1016 fprintf(fd, " ");
1017 fprintf(fd, "%s", IObuff);
1018 }
1019 fclose(sfd);
1020 }
1021 fprintf(fd, "\n");
1022 }
1023 }
1024}
1025
1026/*
1027 * Return TRUE when a function defined in the current script should be
1028 * profiled.
1029 */
1030 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001031prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001032{
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001033 if (current_sctx.sc_sid > 0)
1034 return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001035 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001036}
1037
1038# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039#endif
1040
1041/*
1042 * If 'autowrite' option set, try to write the file.
1043 * Careful: autocommands may make "buf" invalid!
1044 *
1045 * return FAIL for failure, OK otherwise
1046 */
1047 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001048autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001050 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001051 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001052
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 if (!(p_aw || p_awa) || !p_write
1054#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001055 /* never autowrite a "nofile" or "nowrite" buffer */
1056 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001057#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001058 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001059 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001060 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001061 r = buf_write_all(buf, forceit);
1062
1063 /* Writing may succeed but the buffer still changed, e.g., when there is a
1064 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001065 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001066 r = FAIL;
1067 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068}
1069
1070/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001071 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001072 */
1073 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001074autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075{
1076 buf_T *buf;
1077
1078 if (!(p_aw || p_awa) || !p_write)
1079 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001080 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001081 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001083 bufref_T bufref;
1084
1085 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001086
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001088
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001090 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 }
1093}
1094
1095/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001096 * Return TRUE if buffer was changed and cannot be abandoned.
1097 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001100check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001102 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001103 bufref_T bufref;
1104
1105 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001106
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 if ( !forceit
1108 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001109 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1110 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 {
1112#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1113 if ((p_confirm || cmdmod.confirm) && p_write)
1114 {
1115 buf_T *buf2;
1116 int count = 0;
1117
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001118 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001119 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001120 if (bufIsChanged(buf2)
1121 && (buf2->b_ffname != NULL
1122# ifdef FEAT_BROWSE
1123 || cmdmod.browse
1124# endif
1125 ))
1126 ++count;
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 Moolenaarf2bd8ef2018-03-04 18:08:14 +01001130
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001132
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001133 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134 /* Autocommand deleted buffer, oops! It's not changed now. */
1135 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001136 return bufIsChanged(buf);
1137 }
1138#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001139 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +02001140 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001141 else
Bram Moolenaar7a760922018-02-19 23:10:02 +01001142 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143 return TRUE;
1144 }
1145 return FALSE;
1146}
1147
1148#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1149
1150#if defined(FEAT_BROWSE) || defined(PROTO)
1151/*
1152 * When wanting to write a file without a file name, ask the user for a name.
1153 */
1154 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001155browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001156{
1157 if (buf->b_fname == NULL)
1158 {
1159 char_u *fname;
1160
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001161 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1162 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 if (fname != NULL)
1164 {
1165 if (setfname(buf, fname, NULL, TRUE) == OK)
1166 buf->b_flags |= BF_NOTEDITED;
1167 vim_free(fname);
1168 }
1169 }
1170}
1171#endif
1172
1173/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001174 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175 * Must check 'write' option first!
1176 */
1177 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001178dialog_changed(
1179 buf_T *buf,
1180 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001182 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001183 int ret;
1184 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001185 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +02001187 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188 if (checkall)
1189 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1190 else
1191 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1192
Bram Moolenaar8218f602012-04-25 17:32:18 +02001193 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1194 * function. */
1195 ea.append = ea.forceit = FALSE;
1196
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197 if (ret == VIM_YES)
1198 {
1199#ifdef FEAT_BROWSE
1200 /* May get file name, when there is none */
1201 browse_save_fname(buf);
1202#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001203 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1204 buf->b_fname, buf->b_ffname, FALSE) == OK)
1205 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 (void)buf_write_all(buf, FALSE);
1207 }
1208 else if (ret == VIM_NO)
1209 {
1210 unchanged(buf, TRUE);
1211 }
1212 else if (ret == VIM_ALL)
1213 {
1214 /*
1215 * Write all modified files that can be written.
1216 * Skip readonly buffers, these need to be confirmed
1217 * individually.
1218 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001219 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220 {
1221 if (bufIsChanged(buf2)
1222 && (buf2->b_ffname != NULL
1223#ifdef FEAT_BROWSE
1224 || cmdmod.browse
1225#endif
1226 )
1227 && !buf2->b_p_ro)
1228 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001229 bufref_T bufref;
1230
1231 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001232#ifdef FEAT_BROWSE
1233 /* May get file name, when there is none */
1234 browse_save_fname(buf2);
1235#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001236 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1237 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1238 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001239 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001240
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001242 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 }
1245 }
1246 }
1247 else if (ret == VIM_DISCARDALL)
1248 {
1249 /*
1250 * mark all buffers as unchanged
1251 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001252 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253 unchanged(buf2, TRUE);
1254 }
1255}
1256#endif
1257
1258/*
1259 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1260 * hidden, autowriting it or unloading it.
1261 */
1262 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001263can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264{
Bram Moolenaareb44a682017-08-03 22:44:55 +02001265 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 || !bufIsChanged(buf)
1267 || buf->b_nwindows > 1
1268 || autowrite(buf, forceit) == OK
1269 || forceit);
1270}
1271
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001272/*
1273 * Add a buffer number to "bufnrs", unless it's already there.
1274 */
1275 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001276add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001277{
1278 int i;
1279
1280 for (i = 0; i < *bufnump; ++i)
1281 if (bufnrs[i] == nr)
1282 return;
1283 bufnrs[*bufnump] = nr;
1284 *bufnump = *bufnump + 1;
1285}
1286
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287/*
1288 * Return TRUE if any buffer was changed and cannot be abandoned.
1289 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001290 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +01001291 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292 */
1293 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001294check_changed_any(
1295 int hidden, /* Only check hidden buffers */
1296 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001298 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299 buf_T *buf;
1300 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001301 int i;
1302 int bufnum = 0;
1303 int bufcount = 0;
1304 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001305 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001308 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001309 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001310 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001312 if (bufcount == 0)
1313 return FALSE;
1314
1315 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1316 if (bufnrs == NULL)
1317 return FALSE;
1318
1319 /* curbuf */
1320 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001321
1322 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001323 FOR_ALL_WINDOWS(wp)
1324 if (wp->w_buffer != curbuf)
1325 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1326
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001327 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +02001328 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001329 if (tp != curtab)
1330 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1331 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001332
1333 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +02001334 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001335 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1336
1337 for (i = 0; i < bufnum; ++i)
1338 {
1339 buf = buflist_findnr(bufnrs[i]);
1340 if (buf == NULL)
1341 continue;
1342 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1343 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001344 bufref_T bufref;
1345
1346 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001347#ifdef FEAT_TERMINAL
1348 if (term_job_running(buf->b_term))
1349 {
1350 if (term_try_stop_job(buf) == FAIL)
1351 break;
1352 }
1353 else
1354#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001355 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02001356 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001357 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1358 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001359 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001360 break; /* didn't save - still changes */
1361 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362 }
1363
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001364 if (i >= bufnum)
1365 goto theend;
1366
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001367 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001368 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369 exiting = FALSE;
1370#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1371 /*
1372 * When ":confirm" used, don't give an error message.
1373 */
1374 if (!(p_confirm || cmdmod.confirm))
1375#endif
1376 {
1377 /* There must be a wait_return for this message, do_buffer()
1378 * may cause a redraw. But wait_return() is a no-op when vgetc()
1379 * is busy (Quit used from window menu), then make sure we don't
1380 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001381 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001382 {
1383 msg_row = cmdline_row;
1384 msg_col = 0;
1385 msg_didout = FALSE;
1386 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001387 if (
1388#ifdef FEAT_TERMINAL
1389 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001390 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +02001391 buf->b_fname)
1392 :
1393#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001394 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001395 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001396 {
1397 save = no_wait_return;
1398 no_wait_return = FALSE;
1399 wait_return(FALSE);
1400 no_wait_return = save;
1401 }
1402 }
1403
Bram Moolenaar071d4272004-06-13 20:20:40 +00001404 /* Try to find a window that contains the buffer. */
1405 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001406 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407 if (wp->w_buffer == buf)
1408 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001409 bufref_T bufref;
1410
1411 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001412
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001413 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001414
Bram Moolenaarbdace832019-03-02 10:13:42 +01001415 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001416 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001417 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001418 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001420buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001421
1422 /* Open the changed buffer in the current window. */
1423 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001424 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001426theend:
1427 vim_free(bufnrs);
1428 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429}
1430
1431/*
1432 * return FAIL if there is no file name, OK if there is one
1433 * give error message for FAIL
1434 */
1435 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001436check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001437{
1438 if (curbuf->b_ffname == NULL)
1439 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001440 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001441 return FAIL;
1442 }
1443 return OK;
1444}
1445
1446/*
1447 * flush the contents of a buffer, unless it has no file name
1448 *
1449 * return FAIL for failure, OK otherwise
1450 */
1451 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001452buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453{
1454 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456
1457 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1458 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1459 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001461 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01001462 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01001463 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001464 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465 return retval;
1466}
1467
1468/*
1469 * Code to handle the argument list.
1470 */
1471
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001472static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001473static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001474static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001475#define AL_SET 1
1476#define AL_ADD 2
1477#define AL_DEL 3
1478
Bram Moolenaar071d4272004-06-13 20:20:40 +00001479/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001480 * Isolate one argument, taking backticks.
1481 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482 * Return a pointer to the start of the next argument.
1483 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001484 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001485do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486{
1487 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 int inbacktick;
1489
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 inbacktick = FALSE;
1491 for (p = str; *str; ++str)
1492 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001493 /* When the backslash is used for escaping the special meaning of a
1494 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495 if (rem_backslash(str))
1496 {
1497 *p++ = *str++;
1498 *p++ = *str;
1499 }
1500 else
1501 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001502 /* An item ends at a space not in backticks */
1503 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001505 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001507 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508 }
1509 }
1510 str = skipwhite(str);
1511 *p = NUL;
1512
1513 return str;
1514}
1515
Bram Moolenaar86b68352004-12-27 21:59:20 +00001516/*
1517 * Separate the arguments in "str" and return a list of pointers in the
1518 * growarray "gap".
1519 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001520 static int
1521get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001522{
1523 ga_init2(gap, (int)sizeof(char_u *), 20);
1524 while (*str != NUL)
1525 {
1526 if (ga_grow(gap, 1) == FAIL)
1527 {
1528 ga_clear(gap);
1529 return FAIL;
1530 }
1531 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1532
Bram Moolenaar398ee732017-08-03 14:29:14 +02001533 /* If str is escaped, don't handle backslashes or spaces */
1534 if (!escaped)
1535 return OK;
1536
Bram Moolenaar86b68352004-12-27 21:59:20 +00001537 /* Isolate one argument, change it in-place, put a NUL after it. */
1538 str = do_one_arg(str);
1539 }
1540 return OK;
1541}
1542
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001543#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001544/*
1545 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001546 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001547 * Return FAIL or OK.
1548 */
1549 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001550get_arglist_exp(
1551 char_u *str,
1552 int *fcountp,
1553 char_u ***fnamesp,
1554 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001555{
1556 garray_T ga;
1557 int i;
1558
Bram Moolenaar398ee732017-08-03 14:29:14 +02001559 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001560 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001561 if (wig == TRUE)
1562 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1563 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1564 else
1565 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1566 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1567
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001568 ga_clear(&ga);
1569 return i;
1570}
1571#endif
1572
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573/*
1574 * Redefine the argument list.
1575 */
1576 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001577set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001578{
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001579 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581
1582/*
1583 * "what" == AL_SET: Redefine the argument list to 'str'.
1584 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1585 * "what" == AL_DEL: remove files in 'str' from the argument list.
1586 *
1587 * Return FAIL for failure, OK otherwise.
1588 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001590do_arglist(
1591 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01001592 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001593 int after UNUSED, // 0 means before first one
1594 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001595{
1596 garray_T new_ga;
1597 int exp_count;
1598 char_u **exp_files;
1599 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600 char_u *p;
1601 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001602 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603
1604 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001605 * Set default argument for ":argadd" command.
1606 */
1607 if (what == AL_ADD && *str == NUL)
1608 {
1609 if (curbuf->b_ffname == NULL)
1610 return FAIL;
1611 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001612 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001613 }
1614
1615 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 * Collect all file name arguments in "new_ga".
1617 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001618 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001619 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 if (what == AL_DEL)
1622 {
1623 regmatch_T regmatch;
1624 int didone;
1625
1626 /*
1627 * Delete the items: use each item as a regexp and find a match in the
1628 * argument list.
1629 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001630 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001631 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1632 {
1633 p = ((char_u **)new_ga.ga_data)[i];
1634 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1635 if (p == NULL)
1636 break;
1637 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1638 if (regmatch.regprog == NULL)
1639 {
1640 vim_free(p);
1641 break;
1642 }
1643
1644 didone = FALSE;
1645 for (match = 0; match < ARGCOUNT; ++match)
1646 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1647 (colnr_T)0))
1648 {
1649 didone = TRUE;
1650 vim_free(ARGLIST[match].ae_fname);
1651 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1652 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1653 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 if (curwin->w_arg_idx > match)
1655 --curwin->w_arg_idx;
1656 --match;
1657 }
1658
Bram Moolenaar473de612013-06-08 18:19:48 +02001659 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660 vim_free(p);
1661 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001662 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001663 }
1664 ga_clear(&new_ga);
1665 }
1666 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 {
1668 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1669 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1670 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01001671 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001673 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 return FAIL;
1675 }
1676
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 if (what == AL_ADD)
1678 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001679 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680 vim_free(exp_files);
1681 }
1682 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001683 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 }
1685
1686 alist_check_arg_idx();
1687
1688 return OK;
1689}
1690
1691/*
1692 * Check the validity of the arg_idx for each other window.
1693 */
1694 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001695alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001698 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699
Bram Moolenaarf740b292006-02-16 22:11:02 +00001700 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701 if (win->w_alist == curwin->w_alist)
1702 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703}
1704
1705/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001706 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001707 * index.
1708 */
1709 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001710editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001711{
1712 return !(win->w_arg_idx >= WARGCOUNT(win)
1713 || (win->w_buffer->b_fnum
1714 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1715 && (win->w_buffer->b_ffname == NULL
1716 || !(fullpathcmp(
1717 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1718 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
1719}
1720
1721/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722 * Check if window "win" is editing the w_arg_idx file in its argument list.
1723 */
1724 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001725check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001727 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 {
1729 /* We are not editing the current entry in the argument list.
1730 * Set "arg_had_last" if we are editing the last one. */
1731 win->w_arg_idx_invalid = TRUE;
1732 if (win->w_arg_idx != WARGCOUNT(win) - 1
1733 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735 && GARGCOUNT > 0
1736 && win->w_arg_idx < GARGCOUNT
1737 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1738 || (win->w_buffer->b_ffname != NULL
1739 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1740 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1741 arg_had_last = TRUE;
1742 }
1743 else
1744 {
1745 /* We are editing the current entry in the argument list.
1746 * Set "arg_had_last" if it's also the last one */
1747 win->w_arg_idx_invalid = FALSE;
1748 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02001749 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 arg_had_last = TRUE;
1751 }
1752}
1753
1754/*
1755 * ":args", ":argslocal" and ":argsglobal".
1756 */
1757 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001758ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759{
1760 int i;
1761
1762 if (eap->cmdidx != CMD_args)
1763 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 alist_unlink(ALIST(curwin));
1765 if (eap->cmdidx == CMD_argglobal)
1766 ALIST(curwin) = &global_alist;
1767 else /* eap->cmdidx == CMD_arglocal */
1768 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001769 }
1770
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01001771 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 {
1773 /*
1774 * ":args file ..": define new argument list, handle like ":next"
1775 * Also for ":argslocal file .." and ":argsglobal file ..".
1776 */
1777 ex_next(eap);
1778 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001779 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780 {
1781 /*
1782 * ":args": list arguments.
1783 */
1784 if (ARGCOUNT > 0)
1785 {
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001786 char_u **items = (char_u **)alloc(sizeof(char_u *) * ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001787
1788 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001790 /* Overwrite the command, for a short list there is no
1791 * scrolling required and no wait_return(). */
1792 gotocmdline(TRUE);
1793
1794 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001795 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001796 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
1797 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 }
1799 }
1800 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 else if (eap->cmdidx == CMD_arglocal)
1802 {
1803 garray_T *gap = &curwin->w_alist->al_ga;
1804
1805 /*
1806 * ":argslocal": make a local copy of the global argument list.
1807 */
1808 if (ga_grow(gap, GARGCOUNT) == OK)
1809 for (i = 0; i < GARGCOUNT; ++i)
1810 if (GARGLIST[i].ae_fname != NULL)
1811 {
1812 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1813 vim_strsave(GARGLIST[i].ae_fname);
1814 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1815 GARGLIST[i].ae_fnum;
1816 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 }
1818 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819}
1820
1821/*
1822 * ":previous", ":sprevious", ":Next" and ":sNext".
1823 */
1824 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001825ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826{
1827 /* If past the last one already, go to the last one. */
1828 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1829 do_argfile(eap, ARGCOUNT - 1);
1830 else
1831 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1832}
1833
1834/*
1835 * ":rewind", ":first", ":sfirst" and ":srewind".
1836 */
1837 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001838ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839{
1840 do_argfile(eap, 0);
1841}
1842
1843/*
1844 * ":last" and ":slast".
1845 */
1846 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001847ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848{
1849 do_argfile(eap, ARGCOUNT - 1);
1850}
1851
1852/*
1853 * ":argument" and ":sargument".
1854 */
1855 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001856ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857{
1858 int i;
1859
1860 if (eap->addr_count > 0)
1861 i = eap->line2 - 1;
1862 else
1863 i = curwin->w_arg_idx;
1864 do_argfile(eap, i);
1865}
1866
1867/*
1868 * Edit file "argn" of the argument lists.
1869 */
1870 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001871do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872{
1873 int other;
1874 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001875 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876
1877 if (argn < 0 || argn >= ARGCOUNT)
1878 {
1879 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001880 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001882 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001884 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885 }
1886 else
1887 {
1888 setpcmark();
1889#ifdef FEAT_GUI
1890 need_mouse_correct = TRUE;
1891#endif
1892
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00001893 /* split window or create new tab page first */
1894 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 {
1896 if (win_split(0, 0) == FAIL)
1897 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001898 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 }
1900 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901 {
1902 /*
1903 * if 'hidden' set, only check for changed file when re-editing
1904 * the same buffer
1905 */
1906 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02001907 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 {
1909 p = fix_fname(alist_name(&ARGLIST[argn]));
1910 other = otherfile(p);
1911 vim_free(p);
1912 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001913 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001914 && check_changed(curbuf, CCGD_AW
1915 | (other ? 0 : CCGD_MULTWIN)
1916 | (eap->forceit ? CCGD_FORCEIT : 0)
1917 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918 return;
1919 }
1920
1921 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001922 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 arg_had_last = TRUE;
1924
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001925 /* Edit the file; always use the last known line number.
1926 * When it fails (e.g. Abort for already edited file) restore the
1927 * argument index. */
1928 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02001930 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001931 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001932 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001934 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 setmark('\'');
1936 }
1937}
1938
1939/*
1940 * ":next", and commands that behave like it.
1941 */
1942 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001943ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944{
1945 int i;
1946
1947 /*
1948 * check for changed buffer now, if this fails the argument list is not
1949 * redefined.
1950 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02001951 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001953 || !check_changed(curbuf, CCGD_AW
1954 | (eap->forceit ? CCGD_FORCEIT : 0)
1955 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 {
1957 if (*eap->arg != NUL) /* redefine file list */
1958 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001959 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 return;
1961 i = 0;
1962 }
1963 else
1964 i = curwin->w_arg_idx + (int)eap->line2;
1965 do_argfile(eap, i);
1966 }
1967}
1968
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969/*
1970 * ":argedit"
1971 */
1972 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001973ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974{
Bram Moolenaar90305c62017-07-16 15:31:17 +02001975 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001976 // Whether curbuf will be reused, curbuf->b_ffname will be set.
1977 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001979 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02001980 return;
1981#ifdef FEAT_TITLE
1982 maketitle();
1983#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001985 if (curwin->w_arg_idx == 0
1986 && (curbuf->b_ml.ml_flags & ML_EMPTY)
1987 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02001988 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02001990 if (i < ARGCOUNT)
1991 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992}
1993
1994/*
1995 * ":argadd"
1996 */
1997 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001998ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999{
2000 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002001 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
2002 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003#ifdef FEAT_TITLE
2004 maketitle();
2005#endif
2006}
2007
2008/*
2009 * ":argdelete"
2010 */
2011 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002012ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013{
2014 int i;
2015 int n;
2016
2017 if (eap->addr_count > 0)
2018 {
2019 /* ":1,4argdel": Delete all arguments in the range. */
2020 if (eap->line2 > ARGCOUNT)
2021 eap->line2 = ARGCOUNT;
2022 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002023 if (*eap->arg != NUL)
2024 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002025 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002026 else if (n <= 0)
2027 {
2028 /* Don't give an error for ":%argdel" if the list is empty. */
2029 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002030 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002031 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002032 else
2033 {
2034 for (i = eap->line1; i <= eap->line2; ++i)
2035 vim_free(ARGLIST[i - 1].ae_fname);
2036 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2037 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2038 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 if (curwin->w_arg_idx >= eap->line2)
2040 curwin->w_arg_idx -= n;
2041 else if (curwin->w_arg_idx > eap->line1)
2042 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002043 if (ARGCOUNT == 0)
2044 curwin->w_arg_idx = 0;
2045 else if (curwin->w_arg_idx >= ARGCOUNT)
2046 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047 }
2048 }
2049 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002050 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002052 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053#ifdef FEAT_TITLE
2054 maketitle();
2055#endif
2056}
2057
2058/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002059 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 */
2061 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002062ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063{
2064 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002065 win_T *wp;
2066 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01002067 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002069#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002072 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002073#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002074 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002075 int qf_idx;
2076#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002077
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002078#ifndef FEAT_QUICKFIX
2079 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2080 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2081 {
2082 ex_ni(eap);
2083 return;
2084 }
2085#endif
2086
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002087#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002088 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002089 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2090 * great speed improvement. */
2091 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002093#ifdef FEAT_CLIPBOARD
2094 start_global_changes();
2095#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096
2097 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002098 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02002099 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002100 || !check_changed(curbuf, CCGD_AW
2101 | (eap->forceit ? CCGD_FORCEIT : 0)
2102 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002105 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002106 wp = firstwin;
2107 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002108 switch (eap->cmdidx)
2109 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01002110 case CMD_windo:
2111 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2112 i++;
2113 break;
2114 case CMD_tabdo:
2115 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2116 i++;
2117 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002118 case CMD_argdo:
2119 i = eap->line1 - 1;
2120 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002121 default:
2122 break;
2123 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 /* set pcmark now */
2125 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002126 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002127 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002128 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002129 || !buf->b_p_bl); buf = buf->b_next)
2130 if (buf->b_fnum > eap->line2)
2131 {
2132 buf = NULL;
2133 break;
2134 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002135 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002136 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002137 }
2138#ifdef FEAT_QUICKFIX
2139 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2140 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2141 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02002142 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002143 if (qf_size <= 0 || eap->line1 > qf_size)
2144 buf = NULL;
2145 else
2146 {
2147 ex_cc(eap);
2148
2149 buf = curbuf;
2150 i = eap->line1 - 1;
2151 if (eap->addr_count <= 0)
2152 /* default is all the quickfix/location list entries */
2153 eap->line2 = qf_size;
2154 }
2155 }
2156#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157 else
2158 setpcmark();
2159 listcmd_busy = TRUE; /* avoids setting pcmark below */
2160
Bram Moolenaare25bb902015-02-27 20:33:37 +01002161 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 {
2163 if (eap->cmdidx == CMD_argdo)
2164 {
2165 /* go to argument "i" */
2166 if (i == ARGCOUNT)
2167 break;
2168 /* Don't call do_argfile() when already there, it will try
2169 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002170 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002171 {
2172 /* Clear 'shm' to avoid that the file message overwrites
2173 * any output from the command. */
2174 p_shm_save = vim_strsave(p_shm);
2175 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002177 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2178 vim_free(p_shm_save);
2179 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180 if (curwin->w_arg_idx != i)
2181 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 else if (eap->cmdidx == CMD_windo)
2184 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002185 /* go to window "wp" */
2186 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002188 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002189 if (curwin != wp)
2190 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002191 wp = curwin->w_next;
2192 }
2193 else if (eap->cmdidx == CMD_tabdo)
2194 {
2195 /* go to window "tp" */
2196 if (!valid_tabpage(tp))
2197 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002198 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002199 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201 else if (eap->cmdidx == CMD_bufdo)
2202 {
2203 /* Remember the number of the next listed buffer, in case
2204 * ":bwipe" is used or autocommands do something strange. */
2205 next_fnum = -1;
2206 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2207 if (buf->b_p_bl)
2208 {
2209 next_fnum = buf->b_fnum;
2210 break;
2211 }
2212 }
2213
Bram Moolenaara162bc52015-01-07 16:54:21 +01002214 ++i;
2215
Bram Moolenaar071d4272004-06-13 20:20:40 +00002216 /* execute the command */
2217 do_cmdline(eap->arg, eap->getline, eap->cookie,
2218 DOCMD_VERBOSE + DOCMD_NOWAIT);
2219
2220 if (eap->cmdidx == CMD_bufdo)
2221 {
2222 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002223 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224 break;
2225 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02002226 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227 if (buf->b_fnum == next_fnum)
2228 break;
2229 if (buf == NULL)
2230 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002231
2232 /* Go to the next buffer. Clear 'shm' to avoid that the file
2233 * message overwrites any output from the command. */
2234 p_shm_save = vim_strsave(p_shm);
2235 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002236 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002237 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2238 vim_free(p_shm_save);
2239
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002240 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 if (curbuf->b_fnum != next_fnum)
2242 break;
2243 }
2244
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002245#ifdef FEAT_QUICKFIX
2246 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2247 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2248 {
2249 if (i >= qf_size || i >= eap->line2)
2250 break;
2251
2252 qf_idx = qf_get_cur_idx(eap);
2253
2254 ex_cnext(eap);
2255
2256 /* If jumping to the next quickfix entry fails, quit here */
2257 if (qf_get_cur_idx(eap) == qf_idx)
2258 break;
2259 }
2260#endif
2261
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 if (eap->cmdidx == CMD_windo)
2263 {
2264 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01002265
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 /* required when 'scrollbind' has been set */
2267 if (curwin->w_p_scb)
2268 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002270
Bram Moolenaara162bc52015-01-07 16:54:21 +01002271 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2272 if (i+1 > eap->line2)
2273 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002274 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2275 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 }
2277 listcmd_busy = FALSE;
2278 }
2279
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002280#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002281 if (save_ei != NULL)
2282 {
2283 au_event_restore(save_ei);
2284 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2285 curbuf->b_fname, TRUE, curbuf);
2286 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002288#ifdef FEAT_CLIPBOARD
2289 end_global_changes();
2290#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291}
2292
2293/*
2294 * Add files[count] to the arglist of the current window after arg "after".
2295 * The file names in files[count] must have been allocated and are taken over.
2296 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002298 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002299alist_add_list(
2300 int count,
2301 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002302 int after, // where to add: 0 = before first one
2303 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304{
2305 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002306 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307
2308 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2309 {
2310 if (after < 0)
2311 after = 0;
2312 if (after > ARGCOUNT)
2313 after = ARGCOUNT;
2314 if (after < ARGCOUNT)
2315 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2316 (ARGCOUNT - after) * sizeof(aentry_T));
2317 for (i = 0; i < count; ++i)
2318 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002319 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
2320
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002322 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 }
2324 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002325 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2326 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002327 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 }
2329
2330 for (i = 0; i < count; ++i)
2331 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332}
2333
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02002334#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2335/*
2336 * Function given to ExpandGeneric() to obtain the possible arguments of the
2337 * argedit and argdelete commands.
2338 */
2339 char_u *
2340get_arglist_name(expand_T *xp UNUSED, int idx)
2341{
2342 if (idx >= ARGCOUNT)
2343 return NULL;
2344
2345 return alist_name(&ARGLIST[idx]);
2346}
2347#endif
2348
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02002349
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350#ifdef FEAT_EVAL
2351/*
2352 * ":compiler[!] {name}"
2353 */
2354 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002355ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356{
2357 char_u *buf;
2358 char_u *old_cur_comp = NULL;
2359 char_u *p;
2360
2361 if (*eap->arg == NUL)
2362 {
2363 /* List all compiler scripts. */
2364 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2365 /* ) keep the indenter happy... */
2366 }
2367 else
2368 {
2369 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2370 if (buf != NULL)
2371 {
2372 if (eap->forceit)
2373 {
2374 /* ":compiler! {name}" sets global options */
2375 do_cmdline_cmd((char_u *)
2376 "command -nargs=* CompilerSet set <args>");
2377 }
2378 else
2379 {
2380 /* ":compiler! {name}" sets local options.
2381 * To remain backwards compatible "current_compiler" is always
2382 * used. A user's compiler plugin may set it, the distributed
2383 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002384 * "b:current_compiler" and restore "current_compiler".
2385 * Explicitly prepend "g:" to make it work in a function. */
2386 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 if (old_cur_comp != NULL)
2388 old_cur_comp = vim_strsave(old_cur_comp);
2389 do_cmdline_cmd((char_u *)
2390 "command -nargs=* CompilerSet setlocal <args>");
2391 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002392 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002393 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394
2395 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002396 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002397 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 vim_free(buf);
2399
2400 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2401
2402 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002403 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 if (p != NULL)
2405 set_internal_string_var((char_u *)"b:current_compiler", p);
2406
2407 /* Restore "current_compiler" for ":compiler {name}". */
2408 if (!eap->forceit)
2409 {
2410 if (old_cur_comp != NULL)
2411 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002412 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413 old_cur_comp);
2414 vim_free(old_cur_comp);
2415 }
2416 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002417 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418 }
2419 }
2420 }
2421}
2422#endif
2423
2424/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002425 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 */
2427 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002428ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002430 char_u *arg = eap->arg;
2431 char_u *p = skiptowhite(arg);
2432 int len = (int)(p - arg);
2433 int flags = eap->forceit ? DIP_ALL : 0;
2434
2435 if (STRNCMP(arg, "START", len) == 0)
2436 {
2437 flags += DIP_START + DIP_NORTP;
2438 arg = skipwhite(arg + len);
2439 }
2440 else if (STRNCMP(arg, "OPT", len) == 0)
2441 {
2442 flags += DIP_OPT + DIP_NORTP;
2443 arg = skipwhite(arg + len);
2444 }
2445 else if (STRNCMP(arg, "PACK", len) == 0)
2446 {
2447 flags += DIP_START + DIP_OPT + DIP_NORTP;
2448 arg = skipwhite(arg + len);
2449 }
2450 else if (STRNCMP(arg, "ALL", len) == 0)
2451 {
2452 flags += DIP_START + DIP_OPT;
2453 arg = skipwhite(arg + len);
2454 }
2455
2456 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457}
2458
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002460source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002462 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463}
2464
2465/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002466 * Find the file "name" in all directories in "path" and invoke
2467 * "callback(fname, cookie)".
2468 * "name" can contain wildcards.
2469 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2470 * When "flags" has DIP_DIR: find directories instead of files.
2471 * When "flags" has DIP_ERR: give an error message if there is no match.
2472 *
2473 * return FAIL when no file could be sourced, OK otherwise.
2474 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01002475 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002476do_in_path(
2477 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002478 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01002479 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002480 void (*callback)(char_u *fname, void *ck),
2481 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482{
2483 char_u *rtp;
2484 char_u *np;
2485 char_u *buf;
2486 char_u *rtp_copy;
2487 char_u *tail;
2488 int num_files;
2489 char_u **files;
2490 int i;
2491 int did_one = FALSE;
2492#ifdef AMIGA
2493 struct Process *proc = (struct Process *)FindTask(0L);
2494 APTR save_winptr = proc->pr_WindowPtr;
2495
2496 /* Avoid a requester here for a volume that doesn't exist. */
2497 proc->pr_WindowPtr = (APTR)-1L;
2498#endif
2499
2500 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2501 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002502 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 buf = alloc(MAXPATHL);
2504 if (buf != NULL && rtp_copy != NULL)
2505 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002506 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002507 {
2508 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002509 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002510 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002511 verbose_leave();
2512 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002513
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514 /* Loop over all entries in 'runtimepath'. */
2515 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01002516 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02002518 size_t buflen;
2519
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520 /* Copy the path from 'runtimepath' to buf[]. */
2521 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02002522 buflen = STRLEN(buf);
2523
2524 /* Skip after or non-after directories. */
2525 if (flags & (DIP_NOAFTER | DIP_AFTER))
2526 {
2527 int is_after = buflen >= 5
2528 && STRCMP(buf + buflen - 5, "after") == 0;
2529
2530 if ((is_after && (flags & DIP_NOAFTER))
2531 || (!is_after && (flags & DIP_AFTER)))
2532 continue;
2533 }
2534
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002535 if (name == NULL)
2536 {
2537 (*callback)(buf, (void *) &cookie);
2538 if (!did_one)
2539 did_one = (cookie == NULL);
2540 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02002541 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002542 {
2543 add_pathsep(buf);
2544 tail = buf + STRLEN(buf);
2545
2546 /* Loop over all patterns in "name" */
2547 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01002548 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002549 {
2550 /* Append the pattern from "name" to buf[]. */
2551 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2552 "\t ");
2553
2554 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002555 {
2556 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002557 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002558 verbose_leave();
2559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560
2561 /* Expand wildcards, invoke the callback for each match. */
2562 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01002563 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 {
2565 for (i = 0; i < num_files; ++i)
2566 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002567 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01002569 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 break;
2571 }
2572 FreeWild(num_files, files);
2573 }
2574 }
2575 }
2576 }
2577 }
2578 vim_free(buf);
2579 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002580 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002581 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002582 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
2583
2584 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002585 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002586 else if (p_verbose > 0)
2587 {
2588 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002589 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002590 verbose_leave();
2591 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002592 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593
2594#ifdef AMIGA
2595 proc->pr_WindowPtr = save_winptr;
2596#endif
2597
2598 return did_one ? OK : FAIL;
2599}
2600
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002601/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002602 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002603 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002604 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
2605 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002606 * Returns OK when at least one match found, FAIL otherwise.
2607 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002608 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002609 * passed by reference in this case, setting it to NULL indicates that callback
2610 * has done its job.
2611 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002612 static int
2613do_in_path_and_pp(
2614 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002615 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002616 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002617 void (*callback)(char_u *fname, void *ck),
2618 void *cookie)
2619{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002620 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002621 char_u *s;
2622 int len;
2623 char *start_dir = "pack/*/start/*/%s";
2624 char *opt_dir = "pack/*/opt/*/%s";
2625
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002626 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002627 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002628
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002629 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002630 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002631 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002632 s = alloc(len);
2633 if (s == NULL)
2634 return FAIL;
2635 vim_snprintf((char *)s, len, start_dir, name);
2636 done = do_in_path(p_pp, s, flags, callback, cookie);
2637 vim_free(s);
2638 }
2639
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002640 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002641 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002642 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002643 s = alloc(len);
2644 if (s == NULL)
2645 return FAIL;
2646 vim_snprintf((char *)s, len, opt_dir, name);
2647 done = do_in_path(p_pp, s, flags, callback, cookie);
2648 vim_free(s);
2649 }
2650
2651 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002652}
2653
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002654/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002655 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2656 */
2657 int
2658do_in_runtimepath(
2659 char_u *name,
2660 int flags,
2661 void (*callback)(char_u *fname, void *ck),
2662 void *cookie)
2663{
2664 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2665}
2666
2667/*
2668 * Source the file "name" from all directories in 'runtimepath'.
2669 * "name" can contain wildcards.
2670 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2671 *
2672 * return FAIL when no file could be sourced, OK otherwise.
2673 */
2674 int
2675source_runtime(char_u *name, int flags)
2676{
2677 return source_in_path(p_rtp, name, flags);
2678}
2679
2680/*
2681 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2682 */
2683 int
2684source_in_path(char_u *path, char_u *name, int flags)
2685{
2686 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2687}
2688
2689
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002690#if defined(FEAT_EVAL) || defined(PROTO)
2691
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002692/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002693 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002694 */
2695 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002696source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002697{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002698 int num_files;
2699 char_u **files;
2700 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002701
Bram Moolenaarf3654822016-03-04 22:12:23 +01002702 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002703 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002704 for (i = 0; i < num_files; ++i)
2705 (void)do_source(files[i], FALSE, DOSO_NONE);
2706 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002707 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002708}
2709
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002710/*
2711 * Add the package directory to 'runtimepath'.
2712 */
2713 static int
2714add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002715{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002716 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002717 char_u *entry;
2718 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002719 int c;
2720 char_u *new_rtp;
2721 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002722 size_t oldlen;
2723 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002724 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002725 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002726 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002727 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002728 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002729 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002730 char_u *buf = NULL;
2731 char_u *rtp_ffname;
2732 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002733 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002734
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002735 p4 = p3 = p2 = p1 = get_past_head(fname);
2736 for (p = p1; *p; MB_PTR_ADV(p))
2737 if (vim_ispathsep_nocolon(*p))
2738 {
2739 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2740 }
2741
2742 /* now we have:
2743 * rtp/pack/name/start/name
2744 * p4 p3 p2 p1
2745 *
2746 * find the part up to "pack" in 'runtimepath' */
2747 c = *++p4; /* append pathsep in order to expand symlink */
2748 *p4 = NUL;
2749 ffname = fix_fname(fname);
2750 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002751 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002752 return FAIL;
2753
Bram Moolenaar99396d42018-09-08 18:21:16 +02002754 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2755 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002756 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002757 buf = alloc(MAXPATHL);
2758 if (buf == NULL)
2759 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002760 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002761 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002762 char_u *cur_entry = entry;
2763
2764 copy_option_part(&entry, buf, MAXPATHL, ",");
2765 if (insp == NULL)
2766 {
2767 add_pathsep(buf);
2768 rtp_ffname = fix_fname(buf);
2769 if (rtp_ffname == NULL)
2770 goto theend;
2771 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2772 vim_free(rtp_ffname);
2773 if (match)
2774 // Insert "ffname" after this entry (and comma).
2775 insp = entry;
2776 }
2777
2778 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2779 && p > buf
2780 && vim_ispathsep(p[-1])
2781 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2782 {
2783 if (insp == NULL)
2784 // Did not find "ffname" before the first "after" directory,
2785 // insert it before this entry.
2786 insp = cur_entry;
2787 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002788 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002789 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002790 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002791
Bram Moolenaar99396d42018-09-08 18:21:16 +02002792 if (insp == NULL)
2793 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002794 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002795
Bram Moolenaar99396d42018-09-08 18:21:16 +02002796 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002797 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2798 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002799 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002800
2801 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002802 addlen = STRLEN(fname) + 1; // add one for comma
2803 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002804 if (new_rtp == NULL)
2805 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002806
2807 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2808 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002809 keep = (int)(insp - p_rtp);
2810 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002811 new_rtp_len = keep;
2812 if (*insp == NUL)
2813 new_rtp[new_rtp_len++] = ','; // add comma before
2814 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2815 new_rtp_len += addlen - 1;
2816 if (*insp != NUL)
2817 new_rtp[new_rtp_len++] = ','; // add comma after
2818
2819 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002820 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002821 int keep_after = (int)(after_insp - p_rtp);
2822
2823 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2824 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2825 keep_after - keep);
2826 new_rtp_len += keep_after - keep;
2827 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2828 new_rtp_len += afterlen - 1;
2829 new_rtp[new_rtp_len++] = ',';
2830 keep = keep_after;
2831 }
2832
2833 if (p_rtp[keep] != NUL)
2834 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2835 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2836 else
2837 new_rtp[new_rtp_len] = NUL;
2838
2839 if (afterlen > 0 && after_insp == NULL)
2840 {
2841 // Append afterdir when "after" was not found:
2842 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002843 STRCAT(new_rtp, ",");
2844 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002845 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002846
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002847 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2848 vim_free(new_rtp);
2849 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002850
2851theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002852 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002853 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002854 vim_free(afterdir);
2855 return retval;
2856}
2857
2858/*
2859 * Load scripts in "plugin" and "ftdetect" directories of the package.
2860 */
2861 static int
2862load_pack_plugin(char_u *fname)
2863{
2864 static char *plugpat = "%s/plugin/**/*.vim";
2865 static char *ftpat = "%s/ftdetect/*.vim";
2866 int len;
2867 char_u *ffname = fix_fname(fname);
2868 char_u *pat = NULL;
2869 int retval = FAIL;
2870
2871 if (ffname == NULL)
2872 return FAIL;
2873 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2874 pat = alloc(len);
2875 if (pat == NULL)
2876 goto theend;
2877 vim_snprintf((char *)pat, len, plugpat, ffname);
2878 source_all_matches(pat);
2879
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002880 {
2881 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2882
2883 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2884 * found when it loads. */
2885 if (cmd != NULL && eval_to_number(cmd) > 0)
2886 {
2887 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2888 vim_snprintf((char *)pat, len, ftpat, ffname);
2889 source_all_matches(pat);
2890 do_cmdline_cmd((char_u *)"augroup END");
2891 }
2892 vim_free(cmd);
2893 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002894 vim_free(pat);
2895 retval = OK;
2896
2897theend:
2898 vim_free(ffname);
2899 return retval;
2900}
2901
2902/* used for "cookie" of add_pack_plugin() */
2903static int APP_ADD_DIR;
2904static int APP_LOAD;
2905static int APP_BOTH;
2906
2907 static void
2908add_pack_plugin(char_u *fname, void *cookie)
2909{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002910 if (cookie != &APP_LOAD)
2911 {
2912 char_u *buf = alloc(MAXPATHL);
2913 char_u *p;
2914 int found = FALSE;
2915
2916 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002917 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002918 p = p_rtp;
2919 while (*p != NUL)
2920 {
2921 copy_option_part(&p, buf, MAXPATHL, ",");
2922 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2923 {
2924 found = TRUE;
2925 break;
2926 }
2927 }
2928 vim_free(buf);
2929 if (!found)
2930 /* directory is not yet in 'runtimepath', add it */
2931 if (add_pack_dir_to_rtp(fname) == FAIL)
2932 return;
2933 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002934
2935 if (cookie != &APP_ADD_DIR)
2936 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002937}
2938
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002939/*
2940 * Add all packages in the "start" directory to 'runtimepath'.
2941 */
2942 void
2943add_pack_start_dirs(void)
2944{
2945 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2946 add_pack_plugin, &APP_ADD_DIR);
2947}
2948
2949/*
2950 * Load plugins from all packages in the "start" directory.
2951 */
2952 void
2953load_start_packages(void)
2954{
2955 did_source_packages = TRUE;
2956 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2957 add_pack_plugin, &APP_LOAD);
2958}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002959
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002960/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002961 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002962 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002963 */
2964 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002965ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002966{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002967 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002968 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002969 /* First do a round to add all directories to 'runtimepath', then load
2970 * the plugins. This allows for plugins to use an autoload directory
2971 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002972 add_pack_start_dirs();
2973 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002974 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002975}
2976
2977/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002978 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002979 */
2980 void
2981ex_packadd(exarg_T *eap)
2982{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002983 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002984 int len;
2985 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002986 int round;
2987 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002988
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002989 /* Round 1: use "start", round 2: use "opt". */
2990 for (round = 1; round <= 2; ++round)
2991 {
2992 /* Only look under "start" when loading packages wasn't done yet. */
2993 if (round == 1 && did_source_packages)
2994 continue;
2995
2996 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
2997 pat = (char *)alloc(len);
2998 if (pat == NULL)
2999 return;
3000 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
3001 /* The first round don't give a "not found" error, in the second round
3002 * only when nothing was found in the first round. */
3003 res = do_in_path(p_pp, (char_u *)pat,
3004 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
3005 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
3006 vim_free(pat);
3007 }
Bram Moolenaar91715872016-03-03 17:13:03 +01003008}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003009#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01003010
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003011#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012/*
3013 * ":options"
3014 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003016ex_options(
3017 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018{
Bram Moolenaarab6c8582017-08-11 17:15:09 +02003019 vim_setenv((char_u *)"OPTWIN_CMD", (char_u *)(cmdmod.tab ? "tab" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3021}
3022#endif
3023
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003024#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3025
3026# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3027/*
3028 * Detect Python 3 or 2, and initialize 'pyxversion'.
3029 */
3030 void
3031init_pyxversion(void)
3032{
3033 if (p_pyx == 0)
3034 {
3035 if (python3_enabled(FALSE))
3036 p_pyx = 3;
3037 else if (python_enabled(FALSE))
3038 p_pyx = 2;
3039 }
3040}
3041# endif
3042
3043/*
3044 * Does a file contain one of the following strings at the beginning of any
3045 * line?
3046 * "#!(any string)python2" => returns 2
3047 * "#!(any string)python3" => returns 3
3048 * "# requires python 2.x" => returns 2
3049 * "# requires python 3.x" => returns 3
3050 * otherwise return 0.
3051 */
3052 static int
3053requires_py_version(char_u *filename)
3054{
3055 FILE *file;
3056 int requires_py_version = 0;
3057 int i, lines;
3058
3059 lines = (int)p_mls;
3060 if (lines < 0)
3061 lines = 5;
3062
3063 file = mch_fopen((char *)filename, "r");
3064 if (file != NULL)
3065 {
3066 for (i = 0; i < lines; i++)
3067 {
3068 if (vim_fgets(IObuff, IOSIZE, file))
3069 break;
3070 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3071 {
3072 /* Check shebang. */
3073 if (strstr((char *)IObuff + 2, "python2") != NULL)
3074 {
3075 requires_py_version = 2;
3076 break;
3077 }
3078 if (strstr((char *)IObuff + 2, "python3") != NULL)
3079 {
3080 requires_py_version = 3;
3081 break;
3082 }
3083 }
3084 IObuff[21] = '\0';
3085 if (STRCMP("# requires python 2.x", IObuff) == 0)
3086 {
3087 requires_py_version = 2;
3088 break;
3089 }
3090 if (STRCMP("# requires python 3.x", IObuff) == 0)
3091 {
3092 requires_py_version = 3;
3093 break;
3094 }
3095 }
3096 fclose(file);
3097 }
3098 return requires_py_version;
3099}
3100
3101
3102/*
3103 * Source a python file using the requested python version.
3104 */
3105 static void
3106source_pyx_file(exarg_T *eap, char_u *fname)
3107{
3108 exarg_T ex;
3109 int v = requires_py_version(fname);
3110
3111# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3112 init_pyxversion();
3113# endif
3114 if (v == 0)
3115 {
3116# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3117 /* user didn't choose a preference, 'pyx' is used */
3118 v = p_pyx;
3119# elif defined(FEAT_PYTHON)
3120 v = 2;
3121# elif defined(FEAT_PYTHON3)
3122 v = 3;
3123# endif
3124 }
3125
3126 /*
3127 * now source, if required python version is not supported show
3128 * unobtrusive message.
3129 */
3130 if (eap == NULL)
3131 vim_memset(&ex, 0, sizeof(ex));
3132 else
3133 ex = *eap;
3134 ex.arg = fname;
3135 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3136
3137 if (v == 2)
3138 {
3139# ifdef FEAT_PYTHON
3140 ex_pyfile(&ex);
3141# else
3142 vim_snprintf((char *)IObuff, IOSIZE,
3143 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3144 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003145 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003146# endif
3147 return;
3148 }
3149 else
3150 {
3151# ifdef FEAT_PYTHON3
3152 ex_py3file(&ex);
3153# else
3154 vim_snprintf((char *)IObuff, IOSIZE,
3155 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3156 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003157 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003158# endif
3159 return;
3160 }
3161}
3162
3163/*
3164 * ":pyxfile {fname}"
3165 */
3166 void
3167ex_pyxfile(exarg_T *eap)
3168{
3169 source_pyx_file(eap, eap->arg);
3170}
3171
3172/*
3173 * ":pyx"
3174 */
3175 void
3176ex_pyx(exarg_T *eap)
3177{
3178# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3179 init_pyxversion();
3180 if (p_pyx == 2)
3181 ex_python(eap);
3182 else
3183 ex_py3(eap);
3184# elif defined(FEAT_PYTHON)
3185 ex_python(eap);
3186# elif defined(FEAT_PYTHON3)
3187 ex_py3(eap);
3188# endif
3189}
3190
3191/*
3192 * ":pyxdo"
3193 */
3194 void
3195ex_pyxdo(exarg_T *eap)
3196{
3197# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3198 init_pyxversion();
3199 if (p_pyx == 2)
3200 ex_pydo(eap);
3201 else
3202 ex_py3do(eap);
3203# elif defined(FEAT_PYTHON)
3204 ex_pydo(eap);
3205# elif defined(FEAT_PYTHON3)
3206 ex_py3do(eap);
3207# endif
3208}
3209
3210#endif
3211
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212/*
3213 * ":source {fname}"
3214 */
3215 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003216ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217{
3218#ifdef FEAT_BROWSE
3219 if (cmdmod.browse)
3220 {
3221 char_u *fname = NULL;
3222
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003223 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02003224 NULL, NULL,
3225 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 if (fname != NULL)
3227 {
3228 cmd_source(fname, eap);
3229 vim_free(fname);
3230 }
3231 }
3232 else
3233#endif
3234 cmd_source(eap->arg, eap);
3235}
3236
3237 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003238cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239{
3240 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003241 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003244 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003245 * Need to execute the commands directly. This is required at least
3246 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247 * - ":g" command busy
3248 * - after ":argdo", ":windo" or ":bufdo"
3249 * - another command follows
3250 * - inside a loop
3251 */
3252 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3253#ifdef FEAT_EVAL
3254 || eap->cstack->cs_idx >= 0
3255#endif
3256 );
3257
3258 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003259 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003260 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261}
3262
3263/*
3264 * ":source" and associated commands.
3265 */
3266/*
3267 * Structure used to store info for each sourced file.
3268 * It is shared between do_source() and getsourceline().
3269 * This is required, because it needs to be handed to do_cmdline() and
3270 * sourcing can be done recursively.
3271 */
3272struct source_cookie
3273{
3274 FILE *fp; /* opened file for sourcing */
3275 char_u *nextline; /* if not NULL: line that was read ahead */
3276 int finished; /* ":finish" used */
Bram Moolenaar00590742019-02-15 21:06:09 +01003277#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3279 int error; /* TRUE if LF found after CR-LF */
3280#endif
3281#ifdef FEAT_EVAL
3282 linenr_T breakpoint; /* next line with breakpoint or zero */
3283 char_u *fname; /* name of sourced file */
3284 int dbg_tick; /* debug_tick when breakpoint was set */
3285 int level; /* top nesting level of sourced file */
3286#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 vimconv_T conv; /* type of conversion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288};
3289
3290#ifdef FEAT_EVAL
3291/*
3292 * Return the address holding the next breakpoint line for a source cookie.
3293 */
3294 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003295source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296{
3297 return &((struct source_cookie *)cookie)->breakpoint;
3298}
3299
3300/*
3301 * Return the address holding the debug tick for a source cookie.
3302 */
3303 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003304source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003305{
3306 return &((struct source_cookie *)cookie)->dbg_tick;
3307}
3308
3309/*
3310 * Return the nesting level for a source cookie.
3311 */
3312 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003313source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314{
3315 return ((struct source_cookie *)cookie)->level;
3316}
3317#endif
3318
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003319static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320
Bram Moolenaar4f974752019-02-17 17:44:42 +01003321#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003322# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323/*
3324 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003325 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 */
3327 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003328fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003330# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003331 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3332# else
3333 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003334# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335
3336 if (fd_tmp == -1)
3337 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003338
3339# ifdef HAVE_FD_CLOEXEC
3340 {
3341 int fdflags = fcntl(fd_tmp, F_GETFD);
3342 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003343 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003344 }
3345# endif
3346
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347 return fdopen(fd_tmp, READBIN);
3348}
3349#endif
3350
3351
3352/*
3353 * do_source: Read the file "fname" and execute its lines as EX commands.
3354 *
3355 * This function may be called recursively!
3356 *
3357 * return FAIL if file could not be opened, OK otherwise
3358 */
3359 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003360do_source(
3361 char_u *fname,
3362 int check_other, /* check for .vimrc and _vimrc */
3363 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364{
3365 struct source_cookie cookie;
3366 char_u *save_sourcing_name;
3367 linenr_T save_sourcing_lnum;
3368 char_u *p;
3369 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003370 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 int retval = FAIL;
3372#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003373 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003375 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003376 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003378 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003380 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 int stat_ok;
3382# endif
3383#endif
3384#ifdef STARTUPTIME
3385 struct timeval tv_rel;
3386 struct timeval tv_start;
3387#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003388#ifdef FEAT_PROFILE
3389 proftime_T wait_start;
3390#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003391 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392
Bram Moolenaar071d4272004-06-13 20:20:40 +00003393 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 if (p == NULL)
3395 return retval;
3396 fname_exp = fix_fname(p);
3397 vim_free(p);
3398 if (fname_exp == NULL)
3399 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400 if (mch_isdir(fname_exp))
3401 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003402 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003403 goto theend;
3404 }
3405
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003406 /* Apply SourceCmd autocommands, they should get the file and source it. */
3407 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3408 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3409 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003410 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003411#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003412 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003413#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003414 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003415#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003416 if (retval == OK)
3417 // Apply SourcePost autocommands.
3418 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
3419 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003420 goto theend;
3421 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003422
3423 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003424 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003425
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003426#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3428#else
3429 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3430#endif
3431 if (cookie.fp == NULL && check_other)
3432 {
3433 /*
3434 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3435 * and ".exrc" by "_exrc" or vice versa.
3436 */
3437 p = gettail(fname_exp);
3438 if ((*p == '.' || *p == '_')
3439 && (STRICMP(p + 1, "vimrc") == 0
3440 || STRICMP(p + 1, "gvimrc") == 0
3441 || STRICMP(p + 1, "exrc") == 0))
3442 {
3443 if (*p == '_')
3444 *p = '.';
3445 else
3446 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003447#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3449#else
3450 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3451#endif
3452 }
3453 }
3454
3455 if (cookie.fp == NULL)
3456 {
3457 if (p_verbose > 0)
3458 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003459 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003461 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003462 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003463 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003464 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003465 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 }
3467 goto theend;
3468 }
3469
3470 /*
3471 * The file exists.
3472 * - In verbose mode, give a message.
3473 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3474 */
3475 if (p_verbose > 1)
3476 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003477 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003479 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003481 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003482 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003483 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003485 if (is_vimrc == DOSO_VIMRC)
3486 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3487 else if (is_vimrc == DOSO_GVIMRC)
3488 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003489
3490#ifdef USE_CRNL
3491 /* If no automatic file format: Set default to CR-NL. */
3492 if (*p_ffs == NUL)
3493 cookie.fileformat = EOL_DOS;
3494 else
3495 cookie.fileformat = EOL_UNKNOWN;
3496 cookie.error = FALSE;
3497#endif
3498
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 cookie.nextline = NULL;
3500 cookie.finished = FALSE;
3501
3502#ifdef FEAT_EVAL
3503 /*
3504 * Check if this script has a breakpoint.
3505 */
3506 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3507 cookie.fname = fname_exp;
3508 cookie.dbg_tick = debug_tick;
3509
3510 cookie.level = ex_nesting_level;
3511#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512
3513 /*
3514 * Keep the sourcing name/lnum, for recursive calls.
3515 */
3516 save_sourcing_name = sourcing_name;
3517 sourcing_name = fname_exp;
3518 save_sourcing_lnum = sourcing_lnum;
3519 sourcing_lnum = 0;
3520
3521#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003522 if (time_fd != NULL)
3523 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524#endif
3525
3526#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003527# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003528 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003529 prof_child_enter(&wait_start); /* entering a child now */
3530# endif
3531
3532 /* Don't use local function variables, if called from a function.
3533 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003534 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003535
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003536 save_current_sctx = current_sctx;
3537 current_sctx.sc_lnum = 0;
3538 current_sctx.sc_version = 1;
3539
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003540 // Check if this script was sourced before to finds its SID.
3541 // If it's new, generate a new SID.
3542 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003543 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544# ifdef UNIX
3545 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3546# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003547 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
3548 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003549 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003550 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003551 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 && (
3553# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003554 /* Compare dev/ino when possible, it catches symbolic
3555 * links. Also compare file names, the inode may change
3556 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003557 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003558 && (si->sn_dev == st.st_dev
3559 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003561 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003562 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003563 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003564 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003566 current_sctx.sc_sid = ++last_current_SID;
3567 if (ga_grow(&script_items,
3568 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003569 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003570 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003572 ++script_items.ga_len;
3573 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3574# ifdef FEAT_PROFILE
3575 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003578 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003579 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01003580 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00003581# ifdef UNIX
3582 if (stat_ok)
3583 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003584 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003585 si->sn_dev = st.st_dev;
3586 si->sn_ino = st.st_ino;
3587 }
3588 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003589 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003590# endif
3591
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003593 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003594 }
3595
Bram Moolenaar05159a02005-02-26 23:04:13 +00003596# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003597 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003598 {
3599 int forceit;
3600
3601 /* Check if we do profiling for this script. */
3602 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3603 {
3604 script_do_profile(si);
3605 si->sn_pr_force = forceit;
3606 }
3607 if (si->sn_prof_on)
3608 {
3609 ++si->sn_pr_count;
3610 profile_start(&si->sn_pr_start);
3611 profile_zero(&si->sn_pr_children);
3612 }
3613 }
3614# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615#endif
3616
Bram Moolenaar67435d92017-10-19 21:04:37 +02003617 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3618
3619 /* Read the first line so we can check for a UTF-8 BOM. */
3620 firstline = getsourceline(0, (void *)&cookie, 0);
3621 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3622 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3623 {
3624 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3625 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3626 p = string_convert(&cookie.conv, firstline + 3, NULL);
3627 if (p == NULL)
3628 p = vim_strsave(firstline + 3);
3629 if (p != NULL)
3630 {
3631 vim_free(firstline);
3632 firstline = p;
3633 }
3634 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02003635
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636 /*
3637 * Call do_cmdline, which will call getsourceline() to get the lines.
3638 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003639 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003640 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003641 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003642
3643#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003644 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003645 {
3646 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003647 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003648 if (si->sn_prof_on)
3649 {
3650 profile_end(&si->sn_pr_start);
3651 profile_sub_wait(&wait_start, &si->sn_pr_start);
3652 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003653 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3654 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003655 }
3656 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657#endif
3658
3659 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003660 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 sourcing_name = save_sourcing_name;
3662 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 if (p_verbose > 1)
3664 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003665 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003666 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003668 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003669 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670 }
3671#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003672 if (time_fd != NULL)
3673 {
3674 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3675 time_msg((char *)IObuff, &tv_start);
3676 time_pop(&tv_rel);
3677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678#endif
3679
Bram Moolenaar2b618522019-01-12 13:26:03 +01003680 if (!got_int)
3681 trigger_source_post = TRUE;
3682
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683#ifdef FEAT_EVAL
3684 /*
3685 * After a "finish" in debug mode, need to break at first command of next
3686 * sourced file.
3687 */
3688 if (save_debug_break_level > ex_nesting_level
3689 && debug_break_level == ex_nesting_level)
3690 ++debug_break_level;
3691#endif
3692
Bram Moolenaar05159a02005-02-26 23:04:13 +00003693#ifdef FEAT_EVAL
3694almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003695 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003696 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003697# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003698 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003699 prof_child_exit(&wait_start); /* leaving a child now */
3700# endif
3701#endif
3702 fclose(cookie.fp);
3703 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003704 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003705 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003706
Bram Moolenaar2b618522019-01-12 13:26:03 +01003707 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003708 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003709
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710theend:
3711 vim_free(fname_exp);
3712 return retval;
3713}
3714
3715#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003716
Bram Moolenaar071d4272004-06-13 20:20:40 +00003717/*
3718 * ":scriptnames"
3719 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003721ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722{
3723 int i;
3724
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003725 if (eap->addr_count > 0)
3726 {
3727 // :script {scriptId}: edit the script
3728 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003729 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003730 else
3731 {
3732 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3733 do_exedit(eap, NULL);
3734 }
3735 return;
3736 }
3737
Bram Moolenaar05159a02005-02-26 23:04:13 +00003738 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3739 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003740 {
3741 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3742 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003743 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003744 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745}
3746
3747# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3748/*
3749 * Fix slashes in the list of script names for 'shellslash'.
3750 */
3751 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003752scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753{
3754 int i;
3755
Bram Moolenaar05159a02005-02-26 23:04:13 +00003756 for (i = 1; i <= script_items.ga_len; ++i)
3757 if (SCRIPT_ITEM(i).sn_name != NULL)
3758 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003759}
3760# endif
3761
3762/*
3763 * Get a pointer to a script name. Used for ":verbose set".
3764 */
3765 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003766get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767{
3768 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003769 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003770 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003771 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003773 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003775 return (char_u *)_("environment variable");
3776 if (id == SID_ERROR)
3777 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003778 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003779}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003780
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003781# if defined(EXITFREE) || defined(PROTO)
3782 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003783free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003784{
3785 int i;
3786
3787 for (i = script_items.ga_len; i > 0; --i)
3788 vim_free(SCRIPT_ITEM(i).sn_name);
3789 ga_clear(&script_items);
3790}
3791# endif
3792
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793#endif
3794
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795/*
3796 * Get one full line from a sourced file.
3797 * Called by do_cmdline() when it's called from do_source().
3798 *
3799 * Return a pointer to the line in allocated memory.
3800 * Return NULL for end-of-file or some error.
3801 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003803getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804{
3805 struct source_cookie *sp = (struct source_cookie *)cookie;
3806 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003807 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808
3809#ifdef FEAT_EVAL
3810 /* If breakpoints have been added/deleted need to check for it. */
3811 if (sp->dbg_tick < debug_tick)
3812 {
3813 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3814 sp->dbg_tick = debug_tick;
3815 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003816# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003817 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003818 script_line_end();
3819# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820#endif
3821 /*
3822 * Get current line. If there is a read-ahead line, use it, otherwise get
3823 * one now.
3824 */
3825 if (sp->finished)
3826 line = NULL;
3827 else if (sp->nextline == NULL)
3828 line = get_one_sourceline(sp);
3829 else
3830 {
3831 line = sp->nextline;
3832 sp->nextline = NULL;
3833 ++sourcing_lnum;
3834 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003835#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003836 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003837 script_line_start();
3838#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839
3840 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3841 * contain the 'C' flag. */
3842 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3843 {
3844 /* compensate for the one line read-ahead */
3845 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003846
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003847 // Get the next line and concatenate it when it starts with a
3848 // backslash. We always need to read the next line, keep it in
3849 // sp->nextline.
3850 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003851 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003852 if (sp->nextline != NULL
3853 && (*(p = skipwhite(sp->nextline)) == '\\'
3854 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003855 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003856 garray_T ga;
3857
Bram Moolenaarb549a732012-02-22 18:29:33 +01003858 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003859 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003860 if (*p == '\\')
3861 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003862 for (;;)
3863 {
3864 vim_free(sp->nextline);
3865 sp->nextline = get_one_sourceline(sp);
3866 if (sp->nextline == NULL)
3867 break;
3868 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003869 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003870 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003871 // Adjust the growsize to the current length to speed up
3872 // concatenating many lines.
3873 if (ga.ga_len > 400)
3874 {
3875 if (ga.ga_len > 8000)
3876 ga.ga_growsize = 8000;
3877 else
3878 ga.ga_growsize = ga.ga_len;
3879 }
3880 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003881 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003882 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3883 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003884 }
3885 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003887 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888 }
3889 }
3890
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3892 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003893 char_u *s;
3894
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 /* Convert the encoding of the script line. */
3896 s = string_convert(&sp->conv, line, NULL);
3897 if (s != NULL)
3898 {
3899 vim_free(line);
3900 line = s;
3901 }
3902 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003903
3904#ifdef FEAT_EVAL
3905 /* Did we encounter a breakpoint? */
3906 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3907 {
3908 dbg_breakpoint(sp->fname, sourcing_lnum);
3909 /* Find next breakpoint. */
3910 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3911 sp->dbg_tick = debug_tick;
3912 }
3913#endif
3914
3915 return line;
3916}
3917
3918 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003919get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920{
3921 garray_T ga;
3922 int len;
3923 int c;
3924 char_u *buf;
3925#ifdef USE_CRNL
3926 int has_cr; /* CR-LF found */
3927#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003928 int have_read = FALSE;
3929
3930 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003931 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003932
3933 /*
3934 * Loop until there is a finished line (or end-of-file).
3935 */
3936 sourcing_lnum++;
3937 for (;;)
3938 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003939 /* make room to read at least 120 (more) characters */
3940 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003941 break;
3942 buf = (char_u *)ga.ga_data;
3943
Bram Moolenaar00590742019-02-15 21:06:09 +01003944 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003945 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003946 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003947 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948#ifdef USE_CRNL
3949 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3950 * CTRL-Z by its own, or after a NL. */
3951 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3952 && sp->fileformat == EOL_DOS
3953 && buf[len - 1] == Ctrl_Z)
3954 {
3955 buf[len - 1] = NUL;
3956 break;
3957 }
3958#endif
3959
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961 ga.ga_len = len;
3962
3963 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003964 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 continue;
3966
3967 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3968 {
3969#ifdef USE_CRNL
3970 has_cr = (len >= 2 && buf[len - 2] == '\r');
3971 if (sp->fileformat == EOL_UNKNOWN)
3972 {
3973 if (has_cr)
3974 sp->fileformat = EOL_DOS;
3975 else
3976 sp->fileformat = EOL_UNIX;
3977 }
3978
3979 if (sp->fileformat == EOL_DOS)
3980 {
3981 if (has_cr) /* replace trailing CR */
3982 {
3983 buf[len - 2] = '\n';
3984 --len;
3985 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003986 }
3987 else /* lines like ":map xx yy^M" will have failed */
3988 {
3989 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003990 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003991 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003992 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003993 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994 sp->error = TRUE;
3995 sp->fileformat = EOL_UNIX;
3996 }
3997 }
3998#endif
3999 /* The '\n' is escaped if there is an odd number of ^V's just
4000 * before it, first set "c" just before the 'V's and then check
4001 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4002 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4003 ;
4004 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4005 {
4006 sourcing_lnum++;
4007 continue;
4008 }
4009
4010 buf[len - 1] = NUL; /* remove the NL */
4011 }
4012
4013 /*
4014 * Check for ^C here now and then, so recursive :so can be broken.
4015 */
4016 line_breakcheck();
4017 break;
4018 }
4019
4020 if (have_read)
4021 return (char_u *)ga.ga_data;
4022
4023 vim_free(ga.ga_data);
4024 return NULL;
4025}
4026
Bram Moolenaar05159a02005-02-26 23:04:13 +00004027#if defined(FEAT_PROFILE) || defined(PROTO)
4028/*
4029 * Called when starting to read a script line.
4030 * "sourcing_lnum" must be correct!
4031 * When skipping lines it may not actually be executed, but we won't find out
4032 * until later and we need to store the time now.
4033 */
4034 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004035script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004036{
4037 scriptitem_T *si;
4038 sn_prl_T *pp;
4039
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004040 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004041 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004042 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004043 if (si->sn_prof_on && sourcing_lnum >= 1)
4044 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004045 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004046 * here isn't counted. */
Bram Moolenaar67435d92017-10-19 21:04:37 +02004047 (void)ga_grow(&si->sn_prl_ga,
4048 (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004049 si->sn_prl_idx = sourcing_lnum - 1;
4050 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4051 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4052 {
4053 /* Zero counters for a line that was not used before. */
4054 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4055 pp->snp_count = 0;
4056 profile_zero(&pp->sn_prl_total);
4057 profile_zero(&pp->sn_prl_self);
4058 ++si->sn_prl_ga.ga_len;
4059 }
4060 si->sn_prl_execed = FALSE;
4061 profile_start(&si->sn_prl_start);
4062 profile_zero(&si->sn_prl_children);
4063 profile_get_wait(&si->sn_prl_wait);
4064 }
4065}
4066
4067/*
4068 * Called when actually executing a function line.
4069 */
4070 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004071script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004072{
4073 scriptitem_T *si;
4074
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004075 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004076 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004077 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004078 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4079 si->sn_prl_execed = TRUE;
4080}
4081
4082/*
Bram Moolenaar67435d92017-10-19 21:04:37 +02004083 * Called when done with a script line.
Bram Moolenaar05159a02005-02-26 23:04:13 +00004084 */
4085 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004086script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004087{
4088 scriptitem_T *si;
4089 sn_prl_T *pp;
4090
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004091 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004092 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004093 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004094 if (si->sn_prof_on && si->sn_prl_idx >= 0
4095 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4096 {
4097 if (si->sn_prl_execed)
4098 {
4099 pp = &PRL_ITEM(si, si->sn_prl_idx);
4100 ++pp->snp_count;
4101 profile_end(&si->sn_prl_start);
4102 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004103 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004104 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4105 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004106 }
4107 si->sn_prl_idx = -1;
4108 }
4109}
4110#endif
4111
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112/*
4113 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004116ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 struct source_cookie *sp;
4119 char_u *name;
4120
4121 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4122 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004123 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004124 return;
4125 }
4126
4127 if (*eap->arg != NUL)
4128 {
4129 name = enc_canonize(eap->arg);
4130 if (name == NULL) /* out of memory */
4131 return;
4132 }
4133 else
4134 name = eap->arg;
4135
4136 /* Setup for conversion from the specified encoding to 'encoding'. */
4137 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4138 convert_setup(&sp->conv, name, p_enc);
4139
4140 if (name != eap->arg)
4141 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142}
4143
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004144/*
4145 * ":scriptversion": Set Vim script version for a sourced script.
4146 */
4147 void
4148ex_scriptversion(exarg_T *eap UNUSED)
4149{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004150#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004151 int nr;
4152
4153 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4154 {
4155 emsg(_("E984: :scriptversion used outside of a sourced file"));
4156 return;
4157 }
4158
4159 nr = getdigits(&eap->arg);
4160 if (nr == 0 || *eap->arg != NUL)
4161 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02004162 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004163 semsg(_("E999: scriptversion not supported: %d"), nr);
4164 else
4165 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004166#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004167}
4168
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169#if defined(FEAT_EVAL) || defined(PROTO)
4170/*
4171 * ":finish": Mark a sourced file as finished.
4172 */
4173 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004174ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175{
4176 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4177 do_finish(eap, FALSE);
4178 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004179 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180}
4181
4182/*
4183 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4184 * Also called for a pending finish at the ":endtry" or after returning from
4185 * an extra do_cmdline(). "reanimate" is used in the latter case.
4186 */
4187 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004188do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189{
4190 int idx;
4191
4192 if (reanimate)
4193 ((struct source_cookie *)getline_cookie(eap->getline,
4194 eap->cookie))->finished = FALSE;
4195
4196 /*
4197 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4198 * not in its finally clause (which then is to be executed next) is found.
4199 * In this case, make the ":finish" pending for execution at the ":endtry".
4200 * Otherwise, finish normally.
4201 */
4202 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4203 if (idx >= 0)
4204 {
4205 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4206 report_make_pending(CSTP_FINISH, NULL);
4207 }
4208 else
4209 ((struct source_cookie *)getline_cookie(eap->getline,
4210 eap->cookie))->finished = TRUE;
4211}
4212
4213
4214/*
4215 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4216 * message for missing ":endif".
4217 * Return FALSE when not sourcing a file.
4218 */
4219 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004220source_finished(
4221 char_u *(*fgetline)(int, void *, int),
4222 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004224 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004226 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227}
4228#endif
4229
Bram Moolenaar071d4272004-06-13 20:20:40 +00004230/*
4231 * ":checktime [buffer]"
4232 */
4233 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004234ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235{
4236 buf_T *buf;
4237 int save_no_check_timestamps = no_check_timestamps;
4238
4239 no_check_timestamps = 0;
4240 if (eap->addr_count == 0) /* default is all buffers */
4241 check_timestamps(FALSE);
4242 else
4243 {
4244 buf = buflist_findnr((int)eap->line2);
4245 if (buf != NULL) /* cannot happen? */
4246 (void)buf_check_timestamp(buf, FALSE);
4247 }
4248 no_check_timestamps = save_no_check_timestamps;
4249}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250
Bram Moolenaar071d4272004-06-13 20:20:40 +00004251#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4252 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004253# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004254 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004255get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004257 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004258
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004259 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004260 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261
Bram Moolenaar4f974752019-02-17 17:44:42 +01004262# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263 if (loc != NULL)
4264 {
4265 char_u *p;
4266
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004267 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4268 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269 p = vim_strchr(loc, '=');
4270 if (p != NULL)
4271 {
4272 loc = ++p;
4273 while (*p != NUL) /* remove trailing newline */
4274 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004275 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004276 {
4277 *p = NUL;
4278 break;
4279 }
4280 ++p;
4281 }
4282 }
4283 }
4284# endif
4285
4286 return loc;
4287}
4288#endif
4289
4290
Bram Moolenaar4f974752019-02-17 17:44:42 +01004291#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292/*
4293 * On MS-Windows locale names are strings like "German_Germany.1252", but
4294 * gettext expects "de". Try to translate one into another here for a few
4295 * supported languages.
4296 */
4297 static char_u *
4298gettext_lang(char_u *name)
4299{
4300 int i;
4301 static char *(mtable[]) = {
4302 "afrikaans", "af",
4303 "czech", "cs",
4304 "dutch", "nl",
4305 "german", "de",
4306 "english_united kingdom", "en_GB",
4307 "spanish", "es",
4308 "french", "fr",
4309 "italian", "it",
4310 "japanese", "ja",
4311 "korean", "ko",
4312 "norwegian", "no",
4313 "polish", "pl",
4314 "russian", "ru",
4315 "slovak", "sk",
4316 "swedish", "sv",
4317 "ukrainian", "uk",
4318 "chinese_china", "zh_CN",
4319 "chinese_taiwan", "zh_TW",
4320 NULL};
4321
4322 for (i = 0; mtable[i] != NULL; i += 2)
4323 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004324 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325 return name;
4326}
4327#endif
4328
4329#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4330/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01004331 * Return TRUE when "lang" starts with a valid language name.
4332 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
4333 */
4334 static int
4335is_valid_mess_lang(char_u *lang)
4336{
4337 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
4338}
4339
4340/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 * Obtain the current messages language. Used to set the default for
4342 * 'helplang'. May return NULL or an empty string.
4343 */
4344 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004345get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346{
4347 char_u *p;
4348
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004349# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004351 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352# else
4353 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004354 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4355 * and LC_MONETARY may be set differently for a Japanese working in the
4356 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004357 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004358# endif
4359# else
4360 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004361 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 {
4363 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004364 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 p = mch_getenv((char_u *)"LANG");
4366 }
4367# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004368# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 p = gettext_lang(p);
4370# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01004371 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372}
4373#endif
4374
Bram Moolenaardef9e822004-12-31 20:58:58 +00004375/* Complicated #if; matches with where get_mess_env() is used below. */
4376#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4377 && defined(LC_MESSAGES))) \
4378 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00004379 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380/*
4381 * Get the language used for messages from the environment.
4382 */
4383 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004384get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385{
4386 char_u *p;
4387
4388 p = mch_getenv((char_u *)"LC_ALL");
4389 if (p == NULL || *p == NUL)
4390 {
4391 p = mch_getenv((char_u *)"LC_MESSAGES");
4392 if (p == NULL || *p == NUL)
4393 {
4394 p = mch_getenv((char_u *)"LANG");
4395 if (p != NULL && VIM_ISDIGIT(*p))
4396 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004397# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004399 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400# endif
4401 }
4402 }
4403 return p;
4404}
4405#endif
4406
4407#if defined(FEAT_EVAL) || defined(PROTO)
4408
4409/*
4410 * Set the "v:lang" variable according to the current locale setting.
4411 * Also do "v:lc_time"and "v:ctype".
4412 */
4413 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004414set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004415{
4416 char_u *loc;
4417
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004418# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004419 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420# else
4421 /* setlocale() not supported: use the default value */
4422 loc = (char_u *)"C";
4423# endif
4424 set_vim_var_string(VV_CTYPE, loc, -1);
4425
4426 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4427 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004428# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004429 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430# else
4431 loc = get_mess_env();
4432# endif
4433 set_vim_var_string(VV_LANG, loc, -1);
4434
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004435# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004436 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437# endif
4438 set_vim_var_string(VV_LC_TIME, loc, -1);
4439}
4440#endif
4441
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01004442#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443/*
4444 * ":language": Set the language (locale).
4445 */
4446 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004447ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448{
4449 char *loc;
4450 char_u *p;
4451 char_u *name;
4452 int what = LC_ALL;
4453 char *whatstr = "";
4454#ifdef LC_MESSAGES
4455# define VIM_LC_MESSAGES LC_MESSAGES
4456#else
4457# define VIM_LC_MESSAGES 6789
4458#endif
4459
4460 name = eap->arg;
4461
4462 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4463 * Allow abbreviation, but require at least 3 characters to avoid
4464 * confusion with a two letter language name "me" or "ct". */
4465 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004466 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467 {
4468 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4469 {
4470 what = VIM_LC_MESSAGES;
4471 name = skipwhite(p);
4472 whatstr = "messages ";
4473 }
4474 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4475 {
4476 what = LC_CTYPE;
4477 name = skipwhite(p);
4478 whatstr = "ctype ";
4479 }
4480 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4481 {
4482 what = LC_TIME;
4483 name = skipwhite(p);
4484 whatstr = "time ";
4485 }
4486 }
4487
4488 if (*name == NUL)
4489 {
4490#ifndef LC_MESSAGES
4491 if (what == VIM_LC_MESSAGES)
4492 p = get_mess_env();
4493 else
4494#endif
4495 p = (char_u *)setlocale(what, NULL);
4496 if (p == NULL || *p == NUL)
4497 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004498 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 }
4500 else
4501 {
4502#ifndef LC_MESSAGES
4503 if (what == VIM_LC_MESSAGES)
4504 loc = "";
4505 else
4506#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004507 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004509#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4510 /* Make sure strtod() uses a decimal point, not a comma. */
4511 setlocale(LC_NUMERIC, "C");
4512#endif
4513 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004515 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516 else
4517 {
4518#ifdef HAVE_NL_MSG_CAT_CNTR
4519 /* Need to do this for GNU gettext, otherwise cached translations
4520 * will be used again. */
4521 extern int _nl_msg_cat_cntr;
4522
4523 ++_nl_msg_cat_cntr;
4524#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004525 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4527
4528 if (what != LC_TIME)
4529 {
4530 /* Tell gettext() what to translate to. It apparently doesn't
4531 * use the currently effective locale. Also do this when
4532 * FEAT_GETTEXT isn't defined, so that shell commands use this
4533 * value. */
4534 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004535 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004537
4538 /* Clear $LANGUAGE because GNU gettext uses it. */
4539 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01004540# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004541 /* Apparently MS-Windows printf() may cause a crash when
4542 * we give it 8-bit text while it's expecting text in the
4543 * current locale. This call avoids that. */
4544 setlocale(LC_CTYPE, "C");
4545# endif
4546 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004547 if (what != LC_CTYPE)
4548 {
4549 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01004550#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 mname = gettext_lang(name);
4552#else
4553 mname = name;
4554#endif
4555 vim_setenv((char_u *)"LC_MESSAGES", mname);
4556#ifdef FEAT_MULTI_LANG
4557 set_helplang_default(mname);
4558#endif
4559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560 }
4561
4562# ifdef FEAT_EVAL
4563 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4564 set_lang_var();
4565# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004566# ifdef FEAT_TITLE
4567 maketitle();
4568# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004569 }
4570 }
4571}
4572
4573# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004574
4575static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004576
Bram Moolenaar4f974752019-02-17 17:44:42 +01004577# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004578static int did_init_locales = FALSE;
4579
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004580/* Return an array of strings for all available locales + NULL for the
4581 * last element. Return NULL in case of error. */
4582 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004583find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004584{
4585 garray_T locales_ga;
4586 char_u *loc;
4587
4588 /* Find all available locales by running command "locale -a". If this
4589 * doesn't work we won't have completion. */
4590 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004591 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004592 if (locale_a == NULL)
4593 return NULL;
4594 ga_init2(&locales_ga, sizeof(char_u *), 20);
4595
4596 /* Transform locale_a string where each locale is separated by "\n"
4597 * into an array of locale strings. */
4598 loc = (char_u *)strtok((char *)locale_a, "\n");
4599
4600 while (loc != NULL)
4601 {
4602 if (ga_grow(&locales_ga, 1) == FAIL)
4603 break;
4604 loc = vim_strsave(loc);
4605 if (loc == NULL)
4606 break;
4607
4608 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4609 loc = (char_u *)strtok(NULL, "\n");
4610 }
4611 vim_free(locale_a);
4612 if (ga_grow(&locales_ga, 1) == FAIL)
4613 {
4614 ga_clear(&locales_ga);
4615 return NULL;
4616 }
4617 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4618 return (char_u **)locales_ga.ga_data;
4619}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004620# endif
4621
4622/*
4623 * Lazy initialization of all available locales.
4624 */
4625 static void
4626init_locales(void)
4627{
Bram Moolenaar4f974752019-02-17 17:44:42 +01004628# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004629 if (!did_init_locales)
4630 {
4631 did_init_locales = TRUE;
4632 locales = find_locales();
4633 }
4634# endif
4635}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004636
4637# if defined(EXITFREE) || defined(PROTO)
4638 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004639free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004640{
4641 int i;
4642 if (locales != NULL)
4643 {
4644 for (i = 0; locales[i] != NULL; i++)
4645 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004646 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004647 }
4648}
4649# endif
4650
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651/*
4652 * Function given to ExpandGeneric() to obtain the possible arguments of the
4653 * ":language" command.
4654 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004656get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657{
4658 if (idx == 0)
4659 return (char_u *)"messages";
4660 if (idx == 1)
4661 return (char_u *)"ctype";
4662 if (idx == 2)
4663 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004664
4665 init_locales();
4666 if (locales == NULL)
4667 return NULL;
4668 return locales[idx - 3];
4669}
4670
4671/*
4672 * Function given to ExpandGeneric() to obtain the available locales.
4673 */
4674 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004675get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004676{
4677 init_locales();
4678 if (locales == NULL)
4679 return NULL;
4680 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681}
4682# endif
4683
4684#endif