blob: 5a33bb128c3d82fe1870ca3f0e0336e37247b2d9 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar433f7c82006-03-21 21:29:36 +000069# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +000070/*
71 * Store the current time in "tm".
72 */
73 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010074profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +000075{
Bram Moolenaar4f974752019-02-17 17:44:42 +010076# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000077 QueryPerformanceCounter(tm);
78# else
Bram Moolenaar05159a02005-02-26 23:04:13 +000079 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000080# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +000081}
82
83/*
84 * Compute the elapsed time from "tm" till now and store in "tm".
85 */
86 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010087profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +000088{
89 proftime_T now;
90
Bram Moolenaar4f974752019-02-17 17:44:42 +010091# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000092 QueryPerformanceCounter(&now);
93 tm->QuadPart = now.QuadPart - tm->QuadPart;
94# else
Bram Moolenaar05159a02005-02-26 23:04:13 +000095 gettimeofday(&now, NULL);
96 tm->tv_usec = now.tv_usec - tm->tv_usec;
97 tm->tv_sec = now.tv_sec - tm->tv_sec;
98 if (tm->tv_usec < 0)
99 {
100 tm->tv_usec += 1000000;
101 --tm->tv_sec;
102 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000103# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000104}
105
106/*
107 * Subtract the time "tm2" from "tm".
108 */
109 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100110profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000111{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100112# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000113 tm->QuadPart -= tm2->QuadPart;
114# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000115 tm->tv_usec -= tm2->tv_usec;
116 tm->tv_sec -= tm2->tv_sec;
117 if (tm->tv_usec < 0)
118 {
119 tm->tv_usec += 1000000;
120 --tm->tv_sec;
121 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000122# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000123}
124
125/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000126 * Return a string that represents the time in "tm".
127 * Uses a static buffer!
128 */
129 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100130profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000131{
132 static char buf[50];
133
Bram Moolenaar4f974752019-02-17 17:44:42 +0100134# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000135 LARGE_INTEGER fr;
136
137 QueryPerformanceFrequency(&fr);
138 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
139# else
140 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000141# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000142 return buf;
143}
144
Bram Moolenaar79c2c882016-02-07 21:19:28 +0100145# if defined(FEAT_FLOAT) || defined(PROTO)
146/*
147 * Return a float that represents the time in "tm".
148 */
149 float_T
150profile_float(proftime_T *tm)
151{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100152# ifdef MSWIN
Bram Moolenaar79c2c882016-02-07 21:19:28 +0100153 LARGE_INTEGER fr;
154
155 QueryPerformanceFrequency(&fr);
156 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
157# else
158 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
159# endif
160}
161# endif
162
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000163/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000164 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000165 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000166 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100167profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +0000168{
169 if (msec <= 0) /* no limit */
170 profile_zero(tm);
171 else
172 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100173# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +0000174 LARGE_INTEGER fr;
175
176 QueryPerformanceCounter(tm);
177 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000178 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000179# else
180 long usec;
181
182 gettimeofday(tm, NULL);
183 usec = (long)tm->tv_usec + (long)msec * 1000;
184 tm->tv_usec = usec % 1000000L;
185 tm->tv_sec += usec / 1000000L;
186# endif
187 }
188}
189
190/*
191 * Return TRUE if the current time is past "tm".
192 */
193 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100194profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +0000195{
196 proftime_T now;
197
Bram Moolenaar4f974752019-02-17 17:44:42 +0100198# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +0000199 if (tm->QuadPart == 0) /* timer was not set */
200 return FALSE;
201 QueryPerformanceCounter(&now);
202 return (now.QuadPart > tm->QuadPart);
203# else
204 if (tm->tv_sec == 0) /* timer was not set */
205 return FALSE;
206 gettimeofday(&now, NULL);
207 return (now.tv_sec > tm->tv_sec
208 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
209# endif
210}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000211
212/*
213 * Set the time in "tm" to zero.
214 */
215 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100216profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000217{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100218# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000219 tm->QuadPart = 0;
220# else
221 tm->tv_usec = 0;
222 tm->tv_sec = 0;
223# endif
224}
225
Bram Moolenaar76929292008-01-06 19:07:36 +0000226# endif /* FEAT_PROFILE || FEAT_RELTIME */
227
Bram Moolenaar975b5272016-03-15 23:10:59 +0100228# if defined(FEAT_TIMERS) || defined(PROTO)
229static timer_T *first_timer = NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200230static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100231
Bram Moolenaar2f106582019-05-08 21:59:25 +0200232/*
233 * Return time left until "due". Negative if past "due".
234 */
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200235 long
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100236proftime_time_left(proftime_T *due, proftime_T *now)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200237{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100238# ifdef MSWIN
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200239 LARGE_INTEGER fr;
240
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100241 if (now->QuadPart > due->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200242 return 0;
243 QueryPerformanceFrequency(&fr);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100244 return (long)(((double)(due->QuadPart - now->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200245 / (double)fr.QuadPart) * 1000);
246# else
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100247 if (now->tv_sec > due->tv_sec)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200248 return 0;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100249 return (due->tv_sec - now->tv_sec) * 1000
250 + (due->tv_usec - now->tv_usec) / 1000;
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200251# endif
252}
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200253
Bram Moolenaar975b5272016-03-15 23:10:59 +0100254/*
255 * Insert a timer in the list of timers.
256 */
257 static void
258insert_timer(timer_T *timer)
259{
260 timer->tr_next = first_timer;
261 timer->tr_prev = NULL;
262 if (first_timer != NULL)
263 first_timer->tr_prev = timer;
264 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +0200265 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100266}
267
268/*
269 * Take a timer out of the list of timers.
270 */
271 static void
272remove_timer(timer_T *timer)
273{
274 if (timer->tr_prev == NULL)
275 first_timer = timer->tr_next;
276 else
277 timer->tr_prev->tr_next = timer->tr_next;
278 if (timer->tr_next != NULL)
279 timer->tr_next->tr_prev = timer->tr_prev;
280}
281
282 static void
283free_timer(timer_T *timer)
284{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200285 free_callback(&timer->tr_callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200286 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100287}
288
289/*
290 * Create a timer and return it. NULL if out of memory.
291 * Caller should set the callback.
292 */
293 timer_T *
294create_timer(long msec, int repeat)
295{
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200296 timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
Bram Moolenaaree39ef02016-09-10 19:17:42 +0200297 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100298
299 if (timer == NULL)
300 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +0200301 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200302 /* Overflow! Might cause duplicates... */
303 last_timer_id = 0;
304 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100305 insert_timer(timer);
306 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100307 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200308 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100309
310 profile_setlimit(msec, &timer->tr_due);
311 return timer;
312}
313
314/*
315 * Invoke the callback of "timer".
316 */
317 static void
318timer_callback(timer_T *timer)
319{
320 typval_T rettv;
321 int dummy;
322 typval_T argv[2];
323
324 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200325 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100326 argv[1].v_type = VAR_UNKNOWN;
327
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200328 call_callback(&timer->tr_callback, -1,
329 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100330 clear_tv(&rettv);
331}
332
333/*
334 * Call timers that are due.
335 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200336 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100337 */
338 long
Bram Moolenaarcf089462016-06-12 21:18:43 +0200339check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100340{
341 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200342 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100343 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +0100344 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100345 proftime_T now;
346 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200347 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200348 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100349
Bram Moolenaarc577d812017-07-08 22:37:34 +0200350 /* Don't run any timers while exiting or dealing with an error. */
351 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200352 return next_due;
353
Bram Moolenaar75537a92016-09-05 22:45:28 +0200354 profile_start(&now);
355 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100356 {
Bram Moolenaar75537a92016-09-05 22:45:28 +0200357 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200358
Bram Moolenaar75537a92016-09-05 22:45:28 +0200359 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
360 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100361 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200362 if (this_due <= 1)
363 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200364 /* Save and restore a lot of flags, because the timer fires while
365 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200366 int save_timer_busy = timer_busy;
367 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200368 int save_did_emsg = did_emsg;
369 int save_called_emsg = called_emsg;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200370 int save_must_redraw = must_redraw;
Bram Moolenaare723c422017-09-06 23:40:10 +0200371 int save_trylevel = trylevel;
372 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200373 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare723c422017-09-06 23:40:10 +0200374 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200375 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200376
Bram Moolenaare723c422017-09-06 23:40:10 +0200377 /* Create a scope for running the timer callback, ignoring most of
378 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200379 timer_busy = timer_busy > 0 || vgetc_busy > 0;
380 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +0200381 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200382 did_emsg = FALSE;
383 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200384 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +0200385 trylevel = 0;
386 did_throw = FALSE;
387 current_exception = NULL;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200388 save_vimvars(&vvsave);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200389 timer->tr_firing = TRUE;
390 timer_callback(timer);
391 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200392
Bram Moolenaar75537a92016-09-05 22:45:28 +0200393 timer_next = timer->tr_next;
394 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200395 timer_busy = save_timer_busy;
396 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200397 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200398 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200399 did_emsg = save_did_emsg;
400 called_emsg = save_called_emsg;
401 trylevel = save_trylevel;
402 did_throw = save_did_throw;
403 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200404 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200405 if (must_redraw != 0)
406 need_update_screen = TRUE;
407 must_redraw = must_redraw > save_must_redraw
408 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200409 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200410
411 /* Only fire the timer again if it repeats and stop_timer() wasn't
412 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200413 if (timer->tr_repeat != 0 && timer->tr_id != -1
414 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200415 {
416 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100417 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200418 if (this_due < 1)
419 this_due = 1;
420 if (timer->tr_repeat > 0)
421 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100422 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200423 else
424 {
425 this_due = -1;
426 remove_timer(timer);
427 free_timer(timer);
428 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100429 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200430 if (this_due > 0 && (next_due == -1 || next_due > this_due))
431 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100432 }
433
434 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200435 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100436
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100437#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100438 if (bevalexpr_due_set)
439 {
440 this_due = proftime_time_left(&bevalexpr_due, &now);
441 if (this_due <= 1)
442 {
443 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100444 if (balloonEval == NULL)
445 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200446 balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100447 balloonEvalForTerm = TRUE;
448 }
449 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200450 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100451 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200452 setcursor();
453 out_flush();
454 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100455 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200456 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100457 next_due = this_due;
458 }
459#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200460#ifdef FEAT_TERMINAL
461 /* Some terminal windows may need their buffer updated. */
462 next_due = term_check_timers(next_due, &now);
463#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100464
Bram Moolenaar75537a92016-09-05 22:45:28 +0200465 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100466}
467
468/*
469 * Find a timer by ID. Returns NULL if not found;
470 */
471 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200472find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100473{
474 timer_T *timer;
475
Bram Moolenaar75537a92016-09-05 22:45:28 +0200476 if (id >= 0)
477 {
478 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
479 if (timer->tr_id == id)
480 return timer;
481 }
482 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100483}
484
485
486/*
487 * Stop a timer and delete it.
488 */
489 void
490stop_timer(timer_T *timer)
491{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200492 if (timer->tr_firing)
493 /* Free the timer after the callback returns. */
494 timer->tr_id = -1;
495 else
496 {
497 remove_timer(timer);
498 free_timer(timer);
499 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100500}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200501
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200502 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200503stop_all_timers(void)
504{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200505 timer_T *timer;
506 timer_T *timer_next;
507
508 for (timer = first_timer; timer != NULL; timer = timer_next)
509 {
510 timer_next = timer->tr_next;
511 stop_timer(timer);
512 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200513}
514
515 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200516add_timer_info(typval_T *rettv, timer_T *timer)
517{
518 list_T *list = rettv->vval.v_list;
519 dict_T *dict = dict_alloc();
520 dictitem_T *di;
521 long remaining;
522 proftime_T now;
523
524 if (dict == NULL)
525 return;
526 list_append_dict(list, dict);
527
Bram Moolenaare0be1672018-07-08 16:50:37 +0200528 dict_add_number(dict, "id", timer->tr_id);
529 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200530
531 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100532 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200533 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200534
Bram Moolenaare0be1672018-07-08 16:50:37 +0200535 dict_add_number(dict, "repeat",
536 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
537 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200538
539 di = dictitem_alloc((char_u *)"callback");
540 if (di != NULL)
541 {
542 if (dict_add(dict, di) == FAIL)
543 vim_free(di);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200544 else
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200545 put_callback(&timer->tr_callback, &di->di_tv);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200546 }
547}
548
549 void
550add_timer_info_all(typval_T *rettv)
551{
552 timer_T *timer;
553
554 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200555 if (timer->tr_id != -1)
556 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200557}
558
Bram Moolenaare3188e22016-05-31 21:13:04 +0200559/*
560 * Mark references in partials of timers.
561 */
562 int
563set_ref_in_timer(int copyID)
564{
565 int abort = FALSE;
566 timer_T *timer;
567 typval_T tv;
568
569 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
570 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200571 if (timer->tr_callback.cb_partial != NULL)
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200572 {
573 tv.v_type = VAR_PARTIAL;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200574 tv.vval.v_partial = timer->tr_callback.cb_partial;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200575 }
576 else
577 {
578 tv.v_type = VAR_FUNC;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200579 tv.vval.v_string = timer->tr_callback.cb_name;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200580 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200581 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
582 }
583 return abort;
584}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200585
586# if defined(EXITFREE) || defined(PROTO)
587 void
588timer_free_all()
589{
590 timer_T *timer;
591
592 while (first_timer != NULL)
593 {
594 timer = first_timer;
595 remove_timer(timer);
596 free_timer(timer);
597 }
598}
599# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100600# endif
601
Bram Moolenaar113e1072019-01-20 15:30:40 +0100602#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) && defined(FEAT_PROFILE)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200603# if defined(HAVE_MATH_H)
604# include <math.h>
605# endif
606
607/*
608 * Divide the time "tm" by "count" and store in "tm2".
609 */
610 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100611profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200612{
613 if (count == 0)
614 profile_zero(tm2);
615 else
616 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100617# ifdef MSWIN
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200618 tm2->QuadPart = tm->QuadPart / count;
619# else
620 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
621
622 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200623 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200624# endif
625 }
626}
627#endif
628
Bram Moolenaar76929292008-01-06 19:07:36 +0000629# if defined(FEAT_PROFILE) || defined(PROTO)
630/*
631 * Functions for profiling.
632 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100633static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +0000634static proftime_T prof_wait_time;
635
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000636/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000637 * Add the time "tm2" to "tm".
638 */
639 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100640profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000641{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100642# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000643 tm->QuadPart += tm2->QuadPart;
644# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000645 tm->tv_usec += tm2->tv_usec;
646 tm->tv_sec += tm2->tv_sec;
647 if (tm->tv_usec >= 1000000)
648 {
649 tm->tv_usec -= 1000000;
650 ++tm->tv_sec;
651 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000652# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000653}
654
655/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000656 * Add the "self" time from the total time and the children's time.
657 */
658 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100659profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +0000660{
661 /* Check that the result won't be negative. Can happen with recursive
662 * calls. */
Bram Moolenaar4f974752019-02-17 17:44:42 +0100663#ifdef MSWIN
Bram Moolenaar1056d982006-03-09 22:37:52 +0000664 if (total->QuadPart <= children->QuadPart)
665 return;
666#else
667 if (total->tv_sec < children->tv_sec
668 || (total->tv_sec == children->tv_sec
669 && total->tv_usec <= children->tv_usec))
670 return;
671#endif
672 profile_add(self, total);
673 profile_sub(self, children);
674}
675
676/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000677 * Get the current waittime.
678 */
679 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100680profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000681{
682 *tm = prof_wait_time;
683}
684
685/*
686 * Subtract the passed waittime since "tm" from "tma".
687 */
688 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100689profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000690{
691 proftime_T tm3 = prof_wait_time;
692
693 profile_sub(&tm3, tm);
694 profile_sub(tma, &tm3);
695}
696
697/*
698 * Return TRUE if "tm1" and "tm2" are equal.
699 */
700 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100701profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000702{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100703# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000704 return (tm1->QuadPart == tm2->QuadPart);
705# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000706 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000707# endif
708}
709
710/*
711 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
712 */
713 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100714profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000715{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100716# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000717 return (int)(tm2->QuadPart - tm1->QuadPart);
718# else
719 if (tm1->tv_sec == tm2->tv_sec)
720 return tm2->tv_usec - tm1->tv_usec;
721 return tm2->tv_sec - tm1->tv_sec;
722# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000723}
724
Bram Moolenaar05159a02005-02-26 23:04:13 +0000725static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000726static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000727
728/*
729 * ":profile cmd args"
730 */
731 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100732ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000733{
734 char_u *e;
735 int len;
736
737 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000738 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000739 e = skipwhite(e);
740
741 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
742 {
743 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +0200744 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000745 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000746 profile_zero(&prof_wait_time);
747 set_vim_var_nr(VV_PROFILING, 1L);
748 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000749 else if (do_profiling == PROF_NONE)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100750 emsg(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000751 else if (STRCMP(eap->arg, "pause") == 0)
752 {
753 if (do_profiling == PROF_YES)
754 profile_start(&pause_time);
755 do_profiling = PROF_PAUSED;
756 }
757 else if (STRCMP(eap->arg, "continue") == 0)
758 {
759 if (do_profiling == PROF_PAUSED)
760 {
761 profile_end(&pause_time);
762 profile_add(&prof_wait_time, &pause_time);
763 }
764 do_profiling = PROF_YES;
765 }
Bram Moolenaar05159a02005-02-26 23:04:13 +0000766 else
767 {
768 /* The rest is similar to ":breakadd". */
769 ex_breakadd(eap);
770 }
771}
772
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100773/* Command line expansion for :profile. */
774static enum
775{
776 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +0100777 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100778} pexpand_what;
779
780static char *pexpand_cmds[] = {
781 "start",
782#define PROFCMD_START 0
783 "pause",
784#define PROFCMD_PAUSE 1
785 "continue",
786#define PROFCMD_CONTINUE 2
787 "func",
788#define PROFCMD_FUNC 3
789 "file",
790#define PROFCMD_FILE 4
791 NULL
792#define PROFCMD_LAST 5
793};
794
795/*
796 * Function given to ExpandGeneric() to obtain the profile command
797 * specific expansion.
798 */
799 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100800get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100801{
802 switch (pexpand_what)
803 {
804 case PEXP_SUBCMD:
805 return (char_u *)pexpand_cmds[idx];
806 /* case PEXP_FUNC: TODO */
807 default:
808 return NULL;
809 }
810}
811
812/*
813 * Handle command line completion for :profile command.
814 */
815 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100816set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100817{
818 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100819
820 /* Default: expand subcommands. */
821 xp->xp_context = EXPAND_PROFILE;
822 pexpand_what = PEXP_SUBCMD;
823 xp->xp_pattern = arg;
824
825 end_subcmd = skiptowhite(arg);
826 if (*end_subcmd == NUL)
827 return;
828
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +0100829 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100830 {
831 xp->xp_context = EXPAND_FILES;
832 xp->xp_pattern = skipwhite(end_subcmd);
833 return;
834 }
835
836 /* TODO: expand function names after "func" */
837 xp->xp_context = EXPAND_NOTHING;
838}
839
Bram Moolenaar05159a02005-02-26 23:04:13 +0000840/*
841 * Dump the profiling info.
842 */
843 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100844profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 FILE *fd;
847
848 if (profile_fname != NULL)
849 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000850 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000851 if (fd == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100852 semsg(_(e_notopen), profile_fname);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000853 else
854 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000855 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000856 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000857 fclose(fd);
858 }
859 }
860}
861
862/*
863 * Start profiling script "fp".
864 */
865 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100866script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000867{
868 si->sn_pr_count = 0;
869 profile_zero(&si->sn_pr_total);
870 profile_zero(&si->sn_pr_self);
871
872 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
873 si->sn_prl_idx = -1;
874 si->sn_prof_on = TRUE;
875 si->sn_pr_nest = 0;
876}
877
878/*
Bram Moolenaar67435d92017-10-19 21:04:37 +0200879 * Save time when starting to invoke another script or function.
Bram Moolenaar05159a02005-02-26 23:04:13 +0000880 */
881 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100882script_prof_save(
883 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000884{
885 scriptitem_T *si;
886
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200887 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000888 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200889 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000890 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
891 profile_start(&si->sn_pr_child);
892 }
893 profile_get_wait(tm);
894}
895
896/*
897 * Count time spent in children after invoking another script or function.
898 */
899 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100900script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000901{
902 scriptitem_T *si;
903
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200904 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000905 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200906 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000907 if (si->sn_prof_on && --si->sn_pr_nest == 0)
908 {
909 profile_end(&si->sn_pr_child);
910 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
911 profile_add(&si->sn_pr_children, &si->sn_pr_child);
912 profile_add(&si->sn_prl_children, &si->sn_pr_child);
913 }
914 }
915}
916
917static proftime_T inchar_time;
918
919/*
920 * Called when starting to wait for the user to type a character.
921 */
922 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100923prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000924{
925 profile_start(&inchar_time);
926}
927
928/*
929 * Called when finished waiting for the user to type a character.
930 */
931 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100932prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000933{
934 profile_end(&inchar_time);
935 profile_add(&prof_wait_time, &inchar_time);
936}
937
938/*
939 * Dump the profiling results for all scripts in file "fd".
940 */
941 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100942script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943{
944 int id;
945 scriptitem_T *si;
946 int i;
947 FILE *sfd;
948 sn_prl_T *pp;
949
950 for (id = 1; id <= script_items.ga_len; ++id)
951 {
952 si = &SCRIPT_ITEM(id);
953 if (si->sn_prof_on)
954 {
955 fprintf(fd, "SCRIPT %s\n", si->sn_name);
956 if (si->sn_pr_count == 1)
957 fprintf(fd, "Sourced 1 time\n");
958 else
959 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
960 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
961 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
962 fprintf(fd, "\n");
963 fprintf(fd, "count total (s) self (s)\n");
964
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000965 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000966 if (sfd == NULL)
967 fprintf(fd, "Cannot open file!\n");
968 else
969 {
Bram Moolenaar67435d92017-10-19 21:04:37 +0200970 /* Keep going till the end of file, so that trailing
971 * continuation lines are listed. */
972 for (i = 0; ; ++i)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000973 {
974 if (vim_fgets(IObuff, IOSIZE, sfd))
975 break;
Bram Moolenaarac112f02017-12-05 16:46:28 +0100976 /* When a line has been truncated, append NL, taking care
977 * of multi-byte characters . */
978 if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
979 {
980 int n = IOSIZE - 2;
Bram Moolenaar13505972019-01-24 15:04:48 +0100981
Bram Moolenaarac112f02017-12-05 16:46:28 +0100982 if (enc_utf8)
983 {
984 /* Move to the first byte of this char.
985 * utf_head_off() doesn't work, because it checks
986 * for a truncated character. */
987 while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
988 --n;
989 }
990 else if (has_mbyte)
991 n -= mb_head_off(IObuff, IObuff + n);
Bram Moolenaarac112f02017-12-05 16:46:28 +0100992 IObuff[n] = NL;
993 IObuff[n + 1] = NUL;
994 }
Bram Moolenaar67435d92017-10-19 21:04:37 +0200995 if (i < si->sn_prl_ga.ga_len
996 && (pp = &PRL_ITEM(si, i))->snp_count > 0)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000997 {
998 fprintf(fd, "%5d ", pp->snp_count);
999 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1000 fprintf(fd, " ");
1001 else
1002 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1003 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1004 }
1005 else
1006 fprintf(fd, " ");
1007 fprintf(fd, "%s", IObuff);
1008 }
1009 fclose(sfd);
1010 }
1011 fprintf(fd, "\n");
1012 }
1013 }
1014}
1015
1016/*
1017 * Return TRUE when a function defined in the current script should be
1018 * profiled.
1019 */
1020 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001021prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001022{
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001023 if (current_sctx.sc_sid > 0)
1024 return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001025 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001026}
1027
1028# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029#endif
1030
1031/*
1032 * If 'autowrite' option set, try to write the file.
1033 * Careful: autocommands may make "buf" invalid!
1034 *
1035 * return FAIL for failure, OK otherwise
1036 */
1037 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001038autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001040 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001041 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001042
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 if (!(p_aw || p_awa) || !p_write
1044#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001045 /* never autowrite a "nofile" or "nowrite" buffer */
1046 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001048 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001050 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001051 r = buf_write_all(buf, forceit);
1052
1053 /* Writing may succeed but the buffer still changed, e.g., when there is a
1054 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001055 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001056 r = FAIL;
1057 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058}
1059
1060/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001061 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 */
1063 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001064autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065{
1066 buf_T *buf;
1067
1068 if (!(p_aw || p_awa) || !p_write)
1069 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001070 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001071 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001072 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001073 bufref_T bufref;
1074
1075 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001076
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001078
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001080 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 }
1083}
1084
1085/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001086 * Return TRUE if buffer was changed and cannot be abandoned.
1087 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001090check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001092 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001093 bufref_T bufref;
1094
1095 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001096
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 if ( !forceit
1098 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001099 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1100 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 {
1102#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1103 if ((p_confirm || cmdmod.confirm) && p_write)
1104 {
1105 buf_T *buf2;
1106 int count = 0;
1107
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001108 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001109 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 if (bufIsChanged(buf2)
1111 && (buf2->b_ffname != NULL
1112# ifdef FEAT_BROWSE
1113 || cmdmod.browse
1114# endif
1115 ))
1116 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001117 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 /* Autocommand deleted buffer, oops! It's not changed now. */
1119 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001120
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001122
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001123 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 /* Autocommand deleted buffer, oops! It's not changed now. */
1125 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 return bufIsChanged(buf);
1127 }
1128#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001129 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +02001130 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001131 else
Bram Moolenaar7a760922018-02-19 23:10:02 +01001132 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 return TRUE;
1134 }
1135 return FALSE;
1136}
1137
1138#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1139
1140#if defined(FEAT_BROWSE) || defined(PROTO)
1141/*
1142 * When wanting to write a file without a file name, ask the user for a name.
1143 */
1144 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001145browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146{
1147 if (buf->b_fname == NULL)
1148 {
1149 char_u *fname;
1150
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001151 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1152 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 if (fname != NULL)
1154 {
1155 if (setfname(buf, fname, NULL, TRUE) == OK)
1156 buf->b_flags |= BF_NOTEDITED;
1157 vim_free(fname);
1158 }
1159 }
1160}
1161#endif
1162
1163/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001164 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 * Must check 'write' option first!
1166 */
1167 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001168dialog_changed(
1169 buf_T *buf,
1170 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001172 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173 int ret;
1174 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001175 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +02001177 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 if (checkall)
1179 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1180 else
1181 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1182
Bram Moolenaar4ca41532019-05-09 21:48:37 +02001183 // Init ea pseudo-structure, this is needed for the check_overwrite()
1184 // function.
1185 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +02001186
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187 if (ret == VIM_YES)
1188 {
1189#ifdef FEAT_BROWSE
1190 /* May get file name, when there is none */
1191 browse_save_fname(buf);
1192#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001193 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1194 buf->b_fname, buf->b_ffname, FALSE) == OK)
1195 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 (void)buf_write_all(buf, FALSE);
1197 }
1198 else if (ret == VIM_NO)
1199 {
1200 unchanged(buf, TRUE);
1201 }
1202 else if (ret == VIM_ALL)
1203 {
1204 /*
1205 * Write all modified files that can be written.
1206 * Skip readonly buffers, these need to be confirmed
1207 * individually.
1208 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001209 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210 {
1211 if (bufIsChanged(buf2)
1212 && (buf2->b_ffname != NULL
1213#ifdef FEAT_BROWSE
1214 || cmdmod.browse
1215#endif
1216 )
1217 && !buf2->b_p_ro)
1218 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001219 bufref_T bufref;
1220
1221 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222#ifdef FEAT_BROWSE
1223 /* May get file name, when there is none */
1224 browse_save_fname(buf2);
1225#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001226 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1227 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1228 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001230
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001232 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234 }
1235 }
1236 }
1237 else if (ret == VIM_DISCARDALL)
1238 {
1239 /*
1240 * mark all buffers as unchanged
1241 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001242 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243 unchanged(buf2, TRUE);
1244 }
1245}
1246#endif
1247
1248/*
1249 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1250 * hidden, autowriting it or unloading it.
1251 */
1252 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001253can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254{
Bram Moolenaareb44a682017-08-03 22:44:55 +02001255 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 || !bufIsChanged(buf)
1257 || buf->b_nwindows > 1
1258 || autowrite(buf, forceit) == OK
1259 || forceit);
1260}
1261
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001262/*
1263 * Add a buffer number to "bufnrs", unless it's already there.
1264 */
1265 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001266add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001267{
1268 int i;
1269
1270 for (i = 0; i < *bufnump; ++i)
1271 if (bufnrs[i] == nr)
1272 return;
1273 bufnrs[*bufnump] = nr;
1274 *bufnump = *bufnump + 1;
1275}
1276
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277/*
1278 * Return TRUE if any buffer was changed and cannot be abandoned.
1279 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001280 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +01001281 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282 */
1283 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001284check_changed_any(
1285 int hidden, /* Only check hidden buffers */
1286 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001288 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289 buf_T *buf;
1290 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001291 int i;
1292 int bufnum = 0;
1293 int bufcount = 0;
1294 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001295 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001298 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001299 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001300 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001302 if (bufcount == 0)
1303 return FALSE;
1304
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001305 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001306 if (bufnrs == NULL)
1307 return FALSE;
1308
1309 /* curbuf */
1310 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001311
1312 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001313 FOR_ALL_WINDOWS(wp)
1314 if (wp->w_buffer != curbuf)
1315 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1316
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001317 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +02001318 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001319 if (tp != curtab)
1320 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1321 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001322
1323 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +02001324 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001325 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1326
1327 for (i = 0; i < bufnum; ++i)
1328 {
1329 buf = buflist_findnr(bufnrs[i]);
1330 if (buf == NULL)
1331 continue;
1332 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1333 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001334 bufref_T bufref;
1335
1336 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001337#ifdef FEAT_TERMINAL
1338 if (term_job_running(buf->b_term))
1339 {
1340 if (term_try_stop_job(buf) == FAIL)
1341 break;
1342 }
1343 else
1344#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001345 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02001346 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001347 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1348 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001349 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001350 break; /* didn't save - still changes */
1351 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352 }
1353
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001354 if (i >= bufnum)
1355 goto theend;
1356
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001357 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001358 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 exiting = FALSE;
1360#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1361 /*
1362 * When ":confirm" used, don't give an error message.
1363 */
1364 if (!(p_confirm || cmdmod.confirm))
1365#endif
1366 {
1367 /* There must be a wait_return for this message, do_buffer()
1368 * may cause a redraw. But wait_return() is a no-op when vgetc()
1369 * is busy (Quit used from window menu), then make sure we don't
1370 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001371 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372 {
1373 msg_row = cmdline_row;
1374 msg_col = 0;
1375 msg_didout = FALSE;
1376 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001377 if (
1378#ifdef FEAT_TERMINAL
1379 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001380 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +02001381 buf->b_fname)
1382 :
1383#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001384 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001385 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001386 {
1387 save = no_wait_return;
1388 no_wait_return = FALSE;
1389 wait_return(FALSE);
1390 no_wait_return = save;
1391 }
1392 }
1393
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394 /* Try to find a window that contains the buffer. */
1395 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001396 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397 if (wp->w_buffer == buf)
1398 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001399 bufref_T bufref;
1400
1401 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001402
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001403 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001404
Bram Moolenaarbdace832019-03-02 10:13:42 +01001405 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001406 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001407 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001408 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001409 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001410buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411
1412 /* Open the changed buffer in the current window. */
1413 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001414 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001415
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001416theend:
1417 vim_free(bufnrs);
1418 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419}
1420
1421/*
1422 * return FAIL if there is no file name, OK if there is one
1423 * give error message for FAIL
1424 */
1425 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001426check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427{
1428 if (curbuf->b_ffname == NULL)
1429 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001430 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431 return FAIL;
1432 }
1433 return OK;
1434}
1435
1436/*
1437 * flush the contents of a buffer, unless it has no file name
1438 *
1439 * return FAIL for failure, OK otherwise
1440 */
1441 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001442buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443{
1444 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001445 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446
1447 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1448 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1449 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001451 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01001452 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01001453 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455 return retval;
1456}
1457
1458/*
1459 * Code to handle the argument list.
1460 */
1461
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001462static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001463static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001464static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001465#define AL_SET 1
1466#define AL_ADD 2
1467#define AL_DEL 3
1468
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001470 * Isolate one argument, taking backticks.
1471 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001472 * Return a pointer to the start of the next argument.
1473 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001474 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001475do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476{
1477 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478 int inbacktick;
1479
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480 inbacktick = FALSE;
1481 for (p = str; *str; ++str)
1482 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001483 /* When the backslash is used for escaping the special meaning of a
1484 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485 if (rem_backslash(str))
1486 {
1487 *p++ = *str++;
1488 *p++ = *str;
1489 }
1490 else
1491 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001492 /* An item ends at a space not in backticks */
1493 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001495 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001496 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001497 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498 }
1499 }
1500 str = skipwhite(str);
1501 *p = NUL;
1502
1503 return str;
1504}
1505
Bram Moolenaar86b68352004-12-27 21:59:20 +00001506/*
1507 * Separate the arguments in "str" and return a list of pointers in the
1508 * growarray "gap".
1509 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001510 static int
1511get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001512{
1513 ga_init2(gap, (int)sizeof(char_u *), 20);
1514 while (*str != NUL)
1515 {
1516 if (ga_grow(gap, 1) == FAIL)
1517 {
1518 ga_clear(gap);
1519 return FAIL;
1520 }
1521 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1522
Bram Moolenaar398ee732017-08-03 14:29:14 +02001523 /* If str is escaped, don't handle backslashes or spaces */
1524 if (!escaped)
1525 return OK;
1526
Bram Moolenaar86b68352004-12-27 21:59:20 +00001527 /* Isolate one argument, change it in-place, put a NUL after it. */
1528 str = do_one_arg(str);
1529 }
1530 return OK;
1531}
1532
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001533#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001534/*
1535 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001536 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001537 * Return FAIL or OK.
1538 */
1539 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001540get_arglist_exp(
1541 char_u *str,
1542 int *fcountp,
1543 char_u ***fnamesp,
1544 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001545{
1546 garray_T ga;
1547 int i;
1548
Bram Moolenaar398ee732017-08-03 14:29:14 +02001549 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001550 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001551 if (wig == TRUE)
1552 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1553 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1554 else
1555 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1556 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1557
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001558 ga_clear(&ga);
1559 return i;
1560}
1561#endif
1562
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563/*
1564 * Redefine the argument list.
1565 */
1566 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001567set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568{
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001569 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571
1572/*
1573 * "what" == AL_SET: Redefine the argument list to 'str'.
1574 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1575 * "what" == AL_DEL: remove files in 'str' from the argument list.
1576 *
1577 * Return FAIL for failure, OK otherwise.
1578 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001580do_arglist(
1581 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01001582 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001583 int after UNUSED, // 0 means before first one
1584 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001585{
1586 garray_T new_ga;
1587 int exp_count;
1588 char_u **exp_files;
1589 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590 char_u *p;
1591 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001592 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593
1594 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001595 * Set default argument for ":argadd" command.
1596 */
1597 if (what == AL_ADD && *str == NUL)
1598 {
1599 if (curbuf->b_ffname == NULL)
1600 return FAIL;
1601 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001602 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001603 }
1604
1605 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 * Collect all file name arguments in "new_ga".
1607 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001608 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001609 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611 if (what == AL_DEL)
1612 {
1613 regmatch_T regmatch;
1614 int didone;
1615
1616 /*
1617 * Delete the items: use each item as a regexp and find a match in the
1618 * argument list.
1619 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001620 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1622 {
1623 p = ((char_u **)new_ga.ga_data)[i];
1624 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1625 if (p == NULL)
1626 break;
1627 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1628 if (regmatch.regprog == NULL)
1629 {
1630 vim_free(p);
1631 break;
1632 }
1633
1634 didone = FALSE;
1635 for (match = 0; match < ARGCOUNT; ++match)
1636 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1637 (colnr_T)0))
1638 {
1639 didone = TRUE;
1640 vim_free(ARGLIST[match].ae_fname);
1641 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1642 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1643 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001644 if (curwin->w_arg_idx > match)
1645 --curwin->w_arg_idx;
1646 --match;
1647 }
1648
Bram Moolenaar473de612013-06-08 18:19:48 +02001649 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650 vim_free(p);
1651 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001652 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653 }
1654 ga_clear(&new_ga);
1655 }
1656 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657 {
1658 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1659 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1660 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01001661 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001663 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664 return FAIL;
1665 }
1666
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 if (what == AL_ADD)
1668 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001669 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670 vim_free(exp_files);
1671 }
1672 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001673 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 }
1675
1676 alist_check_arg_idx();
1677
1678 return OK;
1679}
1680
1681/*
1682 * Check the validity of the arg_idx for each other window.
1683 */
1684 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001685alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001688 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689
Bram Moolenaarf740b292006-02-16 22:11:02 +00001690 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 if (win->w_alist == curwin->w_alist)
1692 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693}
1694
1695/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001696 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001697 * index.
1698 */
1699 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001700editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001701{
1702 return !(win->w_arg_idx >= WARGCOUNT(win)
1703 || (win->w_buffer->b_fnum
1704 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1705 && (win->w_buffer->b_ffname == NULL
1706 || !(fullpathcmp(
1707 alist_name(&WARGLIST(win)[win->w_arg_idx]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001708 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))));
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001709}
1710
1711/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712 * Check if window "win" is editing the w_arg_idx file in its argument list.
1713 */
1714 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001715check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001717 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001718 {
1719 /* We are not editing the current entry in the argument list.
1720 * Set "arg_had_last" if we are editing the last one. */
1721 win->w_arg_idx_invalid = TRUE;
1722 if (win->w_arg_idx != WARGCOUNT(win) - 1
1723 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 && GARGCOUNT > 0
1726 && win->w_arg_idx < GARGCOUNT
1727 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1728 || (win->w_buffer->b_ffname != NULL
1729 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001730 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731 arg_had_last = TRUE;
1732 }
1733 else
1734 {
1735 /* We are editing the current entry in the argument list.
1736 * Set "arg_had_last" if it's also the last one */
1737 win->w_arg_idx_invalid = FALSE;
1738 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02001739 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 arg_had_last = TRUE;
1741 }
1742}
1743
1744/*
1745 * ":args", ":argslocal" and ":argsglobal".
1746 */
1747 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001748ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749{
1750 int i;
1751
1752 if (eap->cmdidx != CMD_args)
1753 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754 alist_unlink(ALIST(curwin));
1755 if (eap->cmdidx == CMD_argglobal)
1756 ALIST(curwin) = &global_alist;
1757 else /* eap->cmdidx == CMD_arglocal */
1758 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 }
1760
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01001761 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 {
1763 /*
1764 * ":args file ..": define new argument list, handle like ":next"
1765 * Also for ":argslocal file .." and ":argsglobal file ..".
1766 */
1767 ex_next(eap);
1768 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001769 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 {
1771 /*
1772 * ":args": list arguments.
1773 */
1774 if (ARGCOUNT > 0)
1775 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001776 char_u **items = ALLOC_MULT(char_u *, ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001777
1778 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001780 /* Overwrite the command, for a short list there is no
1781 * scrolling required and no wait_return(). */
1782 gotocmdline(TRUE);
1783
1784 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001785 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001786 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
1787 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 }
1789 }
1790 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 else if (eap->cmdidx == CMD_arglocal)
1792 {
1793 garray_T *gap = &curwin->w_alist->al_ga;
1794
1795 /*
1796 * ":argslocal": make a local copy of the global argument list.
1797 */
1798 if (ga_grow(gap, GARGCOUNT) == OK)
1799 for (i = 0; i < GARGCOUNT; ++i)
1800 if (GARGLIST[i].ae_fname != NULL)
1801 {
1802 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1803 vim_strsave(GARGLIST[i].ae_fname);
1804 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1805 GARGLIST[i].ae_fnum;
1806 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807 }
1808 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809}
1810
1811/*
1812 * ":previous", ":sprevious", ":Next" and ":sNext".
1813 */
1814 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001815ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816{
1817 /* If past the last one already, go to the last one. */
1818 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1819 do_argfile(eap, ARGCOUNT - 1);
1820 else
1821 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1822}
1823
1824/*
1825 * ":rewind", ":first", ":sfirst" and ":srewind".
1826 */
1827 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001828ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829{
1830 do_argfile(eap, 0);
1831}
1832
1833/*
1834 * ":last" and ":slast".
1835 */
1836 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001837ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838{
1839 do_argfile(eap, ARGCOUNT - 1);
1840}
1841
1842/*
1843 * ":argument" and ":sargument".
1844 */
1845 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001846ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847{
1848 int i;
1849
1850 if (eap->addr_count > 0)
1851 i = eap->line2 - 1;
1852 else
1853 i = curwin->w_arg_idx;
1854 do_argfile(eap, i);
1855}
1856
1857/*
1858 * Edit file "argn" of the argument lists.
1859 */
1860 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001861do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862{
1863 int other;
1864 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001865 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866
1867 if (argn < 0 || argn >= ARGCOUNT)
1868 {
1869 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001870 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001872 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001874 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 }
1876 else
1877 {
1878 setpcmark();
1879#ifdef FEAT_GUI
1880 need_mouse_correct = TRUE;
1881#endif
1882
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00001883 /* split window or create new tab page first */
1884 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885 {
1886 if (win_split(0, 0) == FAIL)
1887 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001888 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 }
1890 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 {
1892 /*
1893 * if 'hidden' set, only check for changed file when re-editing
1894 * the same buffer
1895 */
1896 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02001897 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 {
1899 p = fix_fname(alist_name(&ARGLIST[argn]));
1900 other = otherfile(p);
1901 vim_free(p);
1902 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001903 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001904 && check_changed(curbuf, CCGD_AW
1905 | (other ? 0 : CCGD_MULTWIN)
1906 | (eap->forceit ? CCGD_FORCEIT : 0)
1907 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 return;
1909 }
1910
1911 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001912 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 arg_had_last = TRUE;
1914
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001915 /* Edit the file; always use the last known line number.
1916 * When it fails (e.g. Abort for already edited file) restore the
1917 * argument index. */
1918 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02001920 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001921 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001922 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001924 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 setmark('\'');
1926 }
1927}
1928
1929/*
1930 * ":next", and commands that behave like it.
1931 */
1932 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001933ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934{
1935 int i;
1936
1937 /*
1938 * check for changed buffer now, if this fails the argument list is not
1939 * redefined.
1940 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02001941 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001943 || !check_changed(curbuf, CCGD_AW
1944 | (eap->forceit ? CCGD_FORCEIT : 0)
1945 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946 {
1947 if (*eap->arg != NUL) /* redefine file list */
1948 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001949 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950 return;
1951 i = 0;
1952 }
1953 else
1954 i = curwin->w_arg_idx + (int)eap->line2;
1955 do_argfile(eap, i);
1956 }
1957}
1958
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959/*
1960 * ":argedit"
1961 */
1962 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001963ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001964{
Bram Moolenaar90305c62017-07-16 15:31:17 +02001965 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001966 // Whether curbuf will be reused, curbuf->b_ffname will be set.
1967 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001969 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02001970 return;
1971#ifdef FEAT_TITLE
1972 maketitle();
1973#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001975 if (curwin->w_arg_idx == 0
1976 && (curbuf->b_ml.ml_flags & ML_EMPTY)
1977 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02001978 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02001980 if (i < ARGCOUNT)
1981 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982}
1983
1984/*
1985 * ":argadd"
1986 */
1987 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001988ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989{
1990 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001991 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
1992 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993#ifdef FEAT_TITLE
1994 maketitle();
1995#endif
1996}
1997
1998/*
1999 * ":argdelete"
2000 */
2001 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002002ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003{
2004 int i;
2005 int n;
2006
2007 if (eap->addr_count > 0)
2008 {
2009 /* ":1,4argdel": Delete all arguments in the range. */
2010 if (eap->line2 > ARGCOUNT)
2011 eap->line2 = ARGCOUNT;
2012 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002013 if (*eap->arg != NUL)
2014 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002015 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002016 else if (n <= 0)
2017 {
2018 /* Don't give an error for ":%argdel" if the list is empty. */
2019 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002020 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002021 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002022 else
2023 {
2024 for (i = eap->line1; i <= eap->line2; ++i)
2025 vim_free(ARGLIST[i - 1].ae_fname);
2026 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2027 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2028 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029 if (curwin->w_arg_idx >= eap->line2)
2030 curwin->w_arg_idx -= n;
2031 else if (curwin->w_arg_idx > eap->line1)
2032 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002033 if (ARGCOUNT == 0)
2034 curwin->w_arg_idx = 0;
2035 else if (curwin->w_arg_idx >= ARGCOUNT)
2036 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002037 }
2038 }
2039 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002040 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002042 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043#ifdef FEAT_TITLE
2044 maketitle();
2045#endif
2046}
2047
2048/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002049 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050 */
2051 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002052ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053{
2054 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002055 win_T *wp;
2056 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01002057 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002059#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002061#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002062 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002063#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002064 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002065 int qf_idx;
2066#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002067
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002068#ifndef FEAT_QUICKFIX
2069 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2070 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2071 {
2072 ex_ni(eap);
2073 return;
2074 }
2075#endif
2076
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002077#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002078 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002079 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2080 * great speed improvement. */
2081 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002083#ifdef FEAT_CLIPBOARD
2084 start_global_changes();
2085#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086
2087 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002088 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02002089 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002090 || !check_changed(curbuf, CCGD_AW
2091 | (eap->forceit ? CCGD_FORCEIT : 0)
2092 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002095 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002096 wp = firstwin;
2097 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002098 switch (eap->cmdidx)
2099 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01002100 case CMD_windo:
2101 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2102 i++;
2103 break;
2104 case CMD_tabdo:
2105 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2106 i++;
2107 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002108 case CMD_argdo:
2109 i = eap->line1 - 1;
2110 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002111 default:
2112 break;
2113 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002114 /* set pcmark now */
2115 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002116 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002117 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002118 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002119 || !buf->b_p_bl); buf = buf->b_next)
2120 if (buf->b_fnum > eap->line2)
2121 {
2122 buf = NULL;
2123 break;
2124 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002125 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002126 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002127 }
2128#ifdef FEAT_QUICKFIX
2129 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2130 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2131 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02002132 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002133 if (qf_size <= 0 || eap->line1 > qf_size)
2134 buf = NULL;
2135 else
2136 {
2137 ex_cc(eap);
2138
2139 buf = curbuf;
2140 i = eap->line1 - 1;
2141 if (eap->addr_count <= 0)
2142 /* default is all the quickfix/location list entries */
2143 eap->line2 = qf_size;
2144 }
2145 }
2146#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 else
2148 setpcmark();
2149 listcmd_busy = TRUE; /* avoids setting pcmark below */
2150
Bram Moolenaare25bb902015-02-27 20:33:37 +01002151 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152 {
2153 if (eap->cmdidx == CMD_argdo)
2154 {
2155 /* go to argument "i" */
2156 if (i == ARGCOUNT)
2157 break;
2158 /* Don't call do_argfile() when already there, it will try
2159 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002160 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002161 {
2162 /* Clear 'shm' to avoid that the file message overwrites
2163 * any output from the command. */
2164 p_shm_save = vim_strsave(p_shm);
2165 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002167 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2168 vim_free(p_shm_save);
2169 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170 if (curwin->w_arg_idx != i)
2171 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002173 else if (eap->cmdidx == CMD_windo)
2174 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002175 /* go to window "wp" */
2176 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002177 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002178 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002179 if (curwin != wp)
2180 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002181 wp = curwin->w_next;
2182 }
2183 else if (eap->cmdidx == CMD_tabdo)
2184 {
2185 /* go to window "tp" */
2186 if (!valid_tabpage(tp))
2187 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002188 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002189 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191 else if (eap->cmdidx == CMD_bufdo)
2192 {
2193 /* Remember the number of the next listed buffer, in case
2194 * ":bwipe" is used or autocommands do something strange. */
2195 next_fnum = -1;
2196 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2197 if (buf->b_p_bl)
2198 {
2199 next_fnum = buf->b_fnum;
2200 break;
2201 }
2202 }
2203
Bram Moolenaara162bc52015-01-07 16:54:21 +01002204 ++i;
2205
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206 /* execute the command */
2207 do_cmdline(eap->arg, eap->getline, eap->cookie,
2208 DOCMD_VERBOSE + DOCMD_NOWAIT);
2209
2210 if (eap->cmdidx == CMD_bufdo)
2211 {
2212 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002213 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002214 break;
2215 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02002216 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 if (buf->b_fnum == next_fnum)
2218 break;
2219 if (buf == NULL)
2220 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002221
2222 /* Go to the next buffer. Clear 'shm' to avoid that the file
2223 * message overwrites any output from the command. */
2224 p_shm_save = vim_strsave(p_shm);
2225 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002227 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2228 vim_free(p_shm_save);
2229
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002230 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231 if (curbuf->b_fnum != next_fnum)
2232 break;
2233 }
2234
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002235#ifdef FEAT_QUICKFIX
2236 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2237 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2238 {
2239 if (i >= qf_size || i >= eap->line2)
2240 break;
2241
2242 qf_idx = qf_get_cur_idx(eap);
2243
2244 ex_cnext(eap);
2245
2246 /* If jumping to the next quickfix entry fails, quit here */
2247 if (qf_get_cur_idx(eap) == qf_idx)
2248 break;
2249 }
2250#endif
2251
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 if (eap->cmdidx == CMD_windo)
2253 {
2254 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01002255
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256 /* required when 'scrollbind' has been set */
2257 if (curwin->w_p_scb)
2258 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002259 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002260
Bram Moolenaara162bc52015-01-07 16:54:21 +01002261 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2262 if (i+1 > eap->line2)
2263 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002264 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2265 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 }
2267 listcmd_busy = FALSE;
2268 }
2269
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002270#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002271 if (save_ei != NULL)
2272 {
2273 au_event_restore(save_ei);
2274 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2275 curbuf->b_fname, TRUE, curbuf);
2276 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002278#ifdef FEAT_CLIPBOARD
2279 end_global_changes();
2280#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281}
2282
2283/*
2284 * Add files[count] to the arglist of the current window after arg "after".
2285 * The file names in files[count] must have been allocated and are taken over.
2286 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002288 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002289alist_add_list(
2290 int count,
2291 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002292 int after, // where to add: 0 = before first one
2293 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294{
2295 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002296 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297
2298 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2299 {
2300 if (after < 0)
2301 after = 0;
2302 if (after > ARGCOUNT)
2303 after = ARGCOUNT;
2304 if (after < ARGCOUNT)
2305 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2306 (ARGCOUNT - after) * sizeof(aentry_T));
2307 for (i = 0; i < count; ++i)
2308 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002309 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
2310
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002312 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 }
2314 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002315 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2316 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002317 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318 }
2319
2320 for (i = 0; i < count; ++i)
2321 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322}
2323
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02002324#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2325/*
2326 * Function given to ExpandGeneric() to obtain the possible arguments of the
2327 * argedit and argdelete commands.
2328 */
2329 char_u *
2330get_arglist_name(expand_T *xp UNUSED, int idx)
2331{
2332 if (idx >= ARGCOUNT)
2333 return NULL;
2334
2335 return alist_name(&ARGLIST[idx]);
2336}
2337#endif
2338
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02002339
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340#ifdef FEAT_EVAL
2341/*
2342 * ":compiler[!] {name}"
2343 */
2344 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002345ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346{
2347 char_u *buf;
2348 char_u *old_cur_comp = NULL;
2349 char_u *p;
2350
2351 if (*eap->arg == NUL)
2352 {
2353 /* List all compiler scripts. */
2354 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2355 /* ) keep the indenter happy... */
2356 }
2357 else
2358 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02002359 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 if (buf != NULL)
2361 {
2362 if (eap->forceit)
2363 {
2364 /* ":compiler! {name}" sets global options */
2365 do_cmdline_cmd((char_u *)
2366 "command -nargs=* CompilerSet set <args>");
2367 }
2368 else
2369 {
2370 /* ":compiler! {name}" sets local options.
2371 * To remain backwards compatible "current_compiler" is always
2372 * used. A user's compiler plugin may set it, the distributed
2373 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002374 * "b:current_compiler" and restore "current_compiler".
2375 * Explicitly prepend "g:" to make it work in a function. */
2376 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 if (old_cur_comp != NULL)
2378 old_cur_comp = vim_strsave(old_cur_comp);
2379 do_cmdline_cmd((char_u *)
2380 "command -nargs=* CompilerSet setlocal <args>");
2381 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002382 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002383 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384
2385 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002386 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002387 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 vim_free(buf);
2389
2390 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2391
2392 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002393 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 if (p != NULL)
2395 set_internal_string_var((char_u *)"b:current_compiler", p);
2396
2397 /* Restore "current_compiler" for ":compiler {name}". */
2398 if (!eap->forceit)
2399 {
2400 if (old_cur_comp != NULL)
2401 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002402 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002403 old_cur_comp);
2404 vim_free(old_cur_comp);
2405 }
2406 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002407 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 }
2409 }
2410 }
2411}
2412#endif
2413
2414/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002415 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 */
2417 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002418ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002420 char_u *arg = eap->arg;
2421 char_u *p = skiptowhite(arg);
2422 int len = (int)(p - arg);
2423 int flags = eap->forceit ? DIP_ALL : 0;
2424
2425 if (STRNCMP(arg, "START", len) == 0)
2426 {
2427 flags += DIP_START + DIP_NORTP;
2428 arg = skipwhite(arg + len);
2429 }
2430 else if (STRNCMP(arg, "OPT", len) == 0)
2431 {
2432 flags += DIP_OPT + DIP_NORTP;
2433 arg = skipwhite(arg + len);
2434 }
2435 else if (STRNCMP(arg, "PACK", len) == 0)
2436 {
2437 flags += DIP_START + DIP_OPT + DIP_NORTP;
2438 arg = skipwhite(arg + len);
2439 }
2440 else if (STRNCMP(arg, "ALL", len) == 0)
2441 {
2442 flags += DIP_START + DIP_OPT;
2443 arg = skipwhite(arg + len);
2444 }
2445
2446 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447}
2448
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002450source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002452 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453}
2454
2455/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002456 * Find the file "name" in all directories in "path" and invoke
2457 * "callback(fname, cookie)".
2458 * "name" can contain wildcards.
2459 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2460 * When "flags" has DIP_DIR: find directories instead of files.
2461 * When "flags" has DIP_ERR: give an error message if there is no match.
2462 *
2463 * return FAIL when no file could be sourced, OK otherwise.
2464 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01002465 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002466do_in_path(
2467 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002468 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01002469 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002470 void (*callback)(char_u *fname, void *ck),
2471 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472{
2473 char_u *rtp;
2474 char_u *np;
2475 char_u *buf;
2476 char_u *rtp_copy;
2477 char_u *tail;
2478 int num_files;
2479 char_u **files;
2480 int i;
2481 int did_one = FALSE;
2482#ifdef AMIGA
2483 struct Process *proc = (struct Process *)FindTask(0L);
2484 APTR save_winptr = proc->pr_WindowPtr;
2485
2486 /* Avoid a requester here for a volume that doesn't exist. */
2487 proc->pr_WindowPtr = (APTR)-1L;
2488#endif
2489
2490 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2491 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002492 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493 buf = alloc(MAXPATHL);
2494 if (buf != NULL && rtp_copy != NULL)
2495 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002496 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002497 {
2498 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002499 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002500 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002501 verbose_leave();
2502 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002503
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 /* Loop over all entries in 'runtimepath'. */
2505 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01002506 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02002508 size_t buflen;
2509
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510 /* Copy the path from 'runtimepath' to buf[]. */
2511 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02002512 buflen = STRLEN(buf);
2513
2514 /* Skip after or non-after directories. */
2515 if (flags & (DIP_NOAFTER | DIP_AFTER))
2516 {
2517 int is_after = buflen >= 5
2518 && STRCMP(buf + buflen - 5, "after") == 0;
2519
2520 if ((is_after && (flags & DIP_NOAFTER))
2521 || (!is_after && (flags & DIP_AFTER)))
2522 continue;
2523 }
2524
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002525 if (name == NULL)
2526 {
2527 (*callback)(buf, (void *) &cookie);
2528 if (!did_one)
2529 did_one = (cookie == NULL);
2530 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02002531 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 {
2533 add_pathsep(buf);
2534 tail = buf + STRLEN(buf);
2535
2536 /* Loop over all patterns in "name" */
2537 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01002538 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 {
2540 /* Append the pattern from "name" to buf[]. */
2541 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2542 "\t ");
2543
2544 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002545 {
2546 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002547 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002548 verbose_leave();
2549 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550
2551 /* Expand wildcards, invoke the callback for each match. */
2552 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01002553 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 {
2555 for (i = 0; i < num_files; ++i)
2556 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002557 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01002559 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 break;
2561 }
2562 FreeWild(num_files, files);
2563 }
2564 }
2565 }
2566 }
2567 }
2568 vim_free(buf);
2569 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002570 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002571 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002572 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
2573
2574 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002575 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002576 else if (p_verbose > 0)
2577 {
2578 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002579 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002580 verbose_leave();
2581 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002582 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583
2584#ifdef AMIGA
2585 proc->pr_WindowPtr = save_winptr;
2586#endif
2587
2588 return did_one ? OK : FAIL;
2589}
2590
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002591/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002592 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002593 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002594 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
2595 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002596 * Returns OK when at least one match found, FAIL otherwise.
2597 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002598 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002599 * passed by reference in this case, setting it to NULL indicates that callback
2600 * has done its job.
2601 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002602 static int
2603do_in_path_and_pp(
2604 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002605 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002606 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002607 void (*callback)(char_u *fname, void *ck),
2608 void *cookie)
2609{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002610 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002611 char_u *s;
2612 int len;
2613 char *start_dir = "pack/*/start/*/%s";
2614 char *opt_dir = "pack/*/opt/*/%s";
2615
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002616 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002617 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002618
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002619 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002620 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002621 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002622 s = alloc(len);
2623 if (s == NULL)
2624 return FAIL;
2625 vim_snprintf((char *)s, len, start_dir, name);
2626 done = do_in_path(p_pp, s, flags, callback, cookie);
2627 vim_free(s);
2628 }
2629
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002630 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002631 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002632 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002633 s = alloc(len);
2634 if (s == NULL)
2635 return FAIL;
2636 vim_snprintf((char *)s, len, opt_dir, name);
2637 done = do_in_path(p_pp, s, flags, callback, cookie);
2638 vim_free(s);
2639 }
2640
2641 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002642}
2643
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002644/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002645 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2646 */
2647 int
2648do_in_runtimepath(
2649 char_u *name,
2650 int flags,
2651 void (*callback)(char_u *fname, void *ck),
2652 void *cookie)
2653{
2654 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2655}
2656
2657/*
2658 * Source the file "name" from all directories in 'runtimepath'.
2659 * "name" can contain wildcards.
2660 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2661 *
2662 * return FAIL when no file could be sourced, OK otherwise.
2663 */
2664 int
2665source_runtime(char_u *name, int flags)
2666{
2667 return source_in_path(p_rtp, name, flags);
2668}
2669
2670/*
2671 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2672 */
2673 int
2674source_in_path(char_u *path, char_u *name, int flags)
2675{
2676 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2677}
2678
2679
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002680#if defined(FEAT_EVAL) || defined(PROTO)
2681
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002682/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002683 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002684 */
2685 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002686source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002687{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002688 int num_files;
2689 char_u **files;
2690 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002691
Bram Moolenaarf3654822016-03-04 22:12:23 +01002692 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002693 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002694 for (i = 0; i < num_files; ++i)
2695 (void)do_source(files[i], FALSE, DOSO_NONE);
2696 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002697 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002698}
2699
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002700/*
2701 * Add the package directory to 'runtimepath'.
2702 */
2703 static int
2704add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002705{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002706 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002707 char_u *entry;
2708 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002709 int c;
2710 char_u *new_rtp;
2711 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002712 size_t oldlen;
2713 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002714 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002715 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002716 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002717 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002718 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002719 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002720 char_u *buf = NULL;
2721 char_u *rtp_ffname;
2722 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002723 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002724
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002725 p4 = p3 = p2 = p1 = get_past_head(fname);
2726 for (p = p1; *p; MB_PTR_ADV(p))
2727 if (vim_ispathsep_nocolon(*p))
2728 {
2729 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2730 }
2731
2732 /* now we have:
2733 * rtp/pack/name/start/name
2734 * p4 p3 p2 p1
2735 *
2736 * find the part up to "pack" in 'runtimepath' */
2737 c = *++p4; /* append pathsep in order to expand symlink */
2738 *p4 = NUL;
2739 ffname = fix_fname(fname);
2740 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002741 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002742 return FAIL;
2743
Bram Moolenaar99396d42018-09-08 18:21:16 +02002744 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2745 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002746 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002747 buf = alloc(MAXPATHL);
2748 if (buf == NULL)
2749 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002750 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002751 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002752 char_u *cur_entry = entry;
2753
2754 copy_option_part(&entry, buf, MAXPATHL, ",");
2755 if (insp == NULL)
2756 {
2757 add_pathsep(buf);
2758 rtp_ffname = fix_fname(buf);
2759 if (rtp_ffname == NULL)
2760 goto theend;
2761 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2762 vim_free(rtp_ffname);
2763 if (match)
2764 // Insert "ffname" after this entry (and comma).
2765 insp = entry;
2766 }
2767
2768 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2769 && p > buf
2770 && vim_ispathsep(p[-1])
2771 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2772 {
2773 if (insp == NULL)
2774 // Did not find "ffname" before the first "after" directory,
2775 // insert it before this entry.
2776 insp = cur_entry;
2777 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002778 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002779 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002780 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002781
Bram Moolenaar99396d42018-09-08 18:21:16 +02002782 if (insp == NULL)
2783 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002784 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002785
Bram Moolenaar99396d42018-09-08 18:21:16 +02002786 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002787 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2788 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002789 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002790
2791 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002792 addlen = STRLEN(fname) + 1; // add one for comma
Bram Moolenaar51e14382019-05-25 20:21:28 +02002793 new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002794 if (new_rtp == NULL)
2795 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002796
2797 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2798 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002799 keep = (int)(insp - p_rtp);
2800 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002801 new_rtp_len = keep;
2802 if (*insp == NUL)
2803 new_rtp[new_rtp_len++] = ','; // add comma before
2804 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2805 new_rtp_len += addlen - 1;
2806 if (*insp != NUL)
2807 new_rtp[new_rtp_len++] = ','; // add comma after
2808
2809 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002810 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002811 int keep_after = (int)(after_insp - p_rtp);
2812
2813 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2814 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2815 keep_after - keep);
2816 new_rtp_len += keep_after - keep;
2817 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2818 new_rtp_len += afterlen - 1;
2819 new_rtp[new_rtp_len++] = ',';
2820 keep = keep_after;
2821 }
2822
2823 if (p_rtp[keep] != NUL)
2824 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2825 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2826 else
2827 new_rtp[new_rtp_len] = NUL;
2828
2829 if (afterlen > 0 && after_insp == NULL)
2830 {
2831 // Append afterdir when "after" was not found:
2832 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002833 STRCAT(new_rtp, ",");
2834 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002835 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002836
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002837 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2838 vim_free(new_rtp);
2839 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002840
2841theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002842 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002843 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002844 vim_free(afterdir);
2845 return retval;
2846}
2847
2848/*
2849 * Load scripts in "plugin" and "ftdetect" directories of the package.
2850 */
2851 static int
2852load_pack_plugin(char_u *fname)
2853{
2854 static char *plugpat = "%s/plugin/**/*.vim";
2855 static char *ftpat = "%s/ftdetect/*.vim";
2856 int len;
2857 char_u *ffname = fix_fname(fname);
2858 char_u *pat = NULL;
2859 int retval = FAIL;
2860
2861 if (ffname == NULL)
2862 return FAIL;
2863 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2864 pat = alloc(len);
2865 if (pat == NULL)
2866 goto theend;
2867 vim_snprintf((char *)pat, len, plugpat, ffname);
2868 source_all_matches(pat);
2869
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002870 {
2871 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2872
2873 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2874 * found when it loads. */
2875 if (cmd != NULL && eval_to_number(cmd) > 0)
2876 {
2877 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2878 vim_snprintf((char *)pat, len, ftpat, ffname);
2879 source_all_matches(pat);
2880 do_cmdline_cmd((char_u *)"augroup END");
2881 }
2882 vim_free(cmd);
2883 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002884 vim_free(pat);
2885 retval = OK;
2886
2887theend:
2888 vim_free(ffname);
2889 return retval;
2890}
2891
2892/* used for "cookie" of add_pack_plugin() */
2893static int APP_ADD_DIR;
2894static int APP_LOAD;
2895static int APP_BOTH;
2896
2897 static void
2898add_pack_plugin(char_u *fname, void *cookie)
2899{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002900 if (cookie != &APP_LOAD)
2901 {
2902 char_u *buf = alloc(MAXPATHL);
2903 char_u *p;
2904 int found = FALSE;
2905
2906 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002907 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002908 p = p_rtp;
2909 while (*p != NUL)
2910 {
2911 copy_option_part(&p, buf, MAXPATHL, ",");
2912 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2913 {
2914 found = TRUE;
2915 break;
2916 }
2917 }
2918 vim_free(buf);
2919 if (!found)
2920 /* directory is not yet in 'runtimepath', add it */
2921 if (add_pack_dir_to_rtp(fname) == FAIL)
2922 return;
2923 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002924
2925 if (cookie != &APP_ADD_DIR)
2926 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002927}
2928
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002929/*
2930 * Add all packages in the "start" directory to 'runtimepath'.
2931 */
2932 void
2933add_pack_start_dirs(void)
2934{
2935 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2936 add_pack_plugin, &APP_ADD_DIR);
2937}
2938
2939/*
2940 * Load plugins from all packages in the "start" directory.
2941 */
2942 void
2943load_start_packages(void)
2944{
2945 did_source_packages = TRUE;
2946 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2947 add_pack_plugin, &APP_LOAD);
2948}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002949
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002950/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002951 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002952 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002953 */
2954 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002955ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002956{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002957 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002958 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002959 /* First do a round to add all directories to 'runtimepath', then load
2960 * the plugins. This allows for plugins to use an autoload directory
2961 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002962 add_pack_start_dirs();
2963 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002964 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002965}
2966
2967/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002968 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002969 */
2970 void
2971ex_packadd(exarg_T *eap)
2972{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002973 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002974 int len;
2975 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002976 int round;
2977 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002978
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002979 /* Round 1: use "start", round 2: use "opt". */
2980 for (round = 1; round <= 2; ++round)
2981 {
2982 /* Only look under "start" when loading packages wasn't done yet. */
2983 if (round == 1 && did_source_packages)
2984 continue;
2985
2986 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002987 pat = alloc(len);
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002988 if (pat == NULL)
2989 return;
2990 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
2991 /* The first round don't give a "not found" error, in the second round
2992 * only when nothing was found in the first round. */
2993 res = do_in_path(p_pp, (char_u *)pat,
2994 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
2995 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
2996 vim_free(pat);
2997 }
Bram Moolenaar91715872016-03-03 17:13:03 +01002998}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002999#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01003000
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003001#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002/*
3003 * ":options"
3004 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003006ex_options(
3007 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008{
Bram Moolenaare0b59492019-05-21 20:54:45 +02003009 vim_setenv((char_u *)"OPTWIN_CMD",
3010 (char_u *)(cmdmod.tab ? "tab"
3011 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3013}
3014#endif
3015
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003016#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3017
3018# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3019/*
3020 * Detect Python 3 or 2, and initialize 'pyxversion'.
3021 */
3022 void
3023init_pyxversion(void)
3024{
3025 if (p_pyx == 0)
3026 {
3027 if (python3_enabled(FALSE))
3028 p_pyx = 3;
3029 else if (python_enabled(FALSE))
3030 p_pyx = 2;
3031 }
3032}
3033# endif
3034
3035/*
3036 * Does a file contain one of the following strings at the beginning of any
3037 * line?
3038 * "#!(any string)python2" => returns 2
3039 * "#!(any string)python3" => returns 3
3040 * "# requires python 2.x" => returns 2
3041 * "# requires python 3.x" => returns 3
3042 * otherwise return 0.
3043 */
3044 static int
3045requires_py_version(char_u *filename)
3046{
3047 FILE *file;
3048 int requires_py_version = 0;
3049 int i, lines;
3050
3051 lines = (int)p_mls;
3052 if (lines < 0)
3053 lines = 5;
3054
3055 file = mch_fopen((char *)filename, "r");
3056 if (file != NULL)
3057 {
3058 for (i = 0; i < lines; i++)
3059 {
3060 if (vim_fgets(IObuff, IOSIZE, file))
3061 break;
3062 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3063 {
3064 /* Check shebang. */
3065 if (strstr((char *)IObuff + 2, "python2") != NULL)
3066 {
3067 requires_py_version = 2;
3068 break;
3069 }
3070 if (strstr((char *)IObuff + 2, "python3") != NULL)
3071 {
3072 requires_py_version = 3;
3073 break;
3074 }
3075 }
3076 IObuff[21] = '\0';
3077 if (STRCMP("# requires python 2.x", IObuff) == 0)
3078 {
3079 requires_py_version = 2;
3080 break;
3081 }
3082 if (STRCMP("# requires python 3.x", IObuff) == 0)
3083 {
3084 requires_py_version = 3;
3085 break;
3086 }
3087 }
3088 fclose(file);
3089 }
3090 return requires_py_version;
3091}
3092
3093
3094/*
3095 * Source a python file using the requested python version.
3096 */
3097 static void
3098source_pyx_file(exarg_T *eap, char_u *fname)
3099{
3100 exarg_T ex;
3101 int v = requires_py_version(fname);
3102
3103# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3104 init_pyxversion();
3105# endif
3106 if (v == 0)
3107 {
3108# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3109 /* user didn't choose a preference, 'pyx' is used */
3110 v = p_pyx;
3111# elif defined(FEAT_PYTHON)
3112 v = 2;
3113# elif defined(FEAT_PYTHON3)
3114 v = 3;
3115# endif
3116 }
3117
3118 /*
3119 * now source, if required python version is not supported show
3120 * unobtrusive message.
3121 */
3122 if (eap == NULL)
3123 vim_memset(&ex, 0, sizeof(ex));
3124 else
3125 ex = *eap;
3126 ex.arg = fname;
3127 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3128
3129 if (v == 2)
3130 {
3131# ifdef FEAT_PYTHON
3132 ex_pyfile(&ex);
3133# else
3134 vim_snprintf((char *)IObuff, IOSIZE,
3135 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3136 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003137 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003138# endif
3139 return;
3140 }
3141 else
3142 {
3143# ifdef FEAT_PYTHON3
3144 ex_py3file(&ex);
3145# else
3146 vim_snprintf((char *)IObuff, IOSIZE,
3147 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3148 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003149 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003150# endif
3151 return;
3152 }
3153}
3154
3155/*
3156 * ":pyxfile {fname}"
3157 */
3158 void
3159ex_pyxfile(exarg_T *eap)
3160{
3161 source_pyx_file(eap, eap->arg);
3162}
3163
3164/*
3165 * ":pyx"
3166 */
3167 void
3168ex_pyx(exarg_T *eap)
3169{
3170# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3171 init_pyxversion();
3172 if (p_pyx == 2)
3173 ex_python(eap);
3174 else
3175 ex_py3(eap);
3176# elif defined(FEAT_PYTHON)
3177 ex_python(eap);
3178# elif defined(FEAT_PYTHON3)
3179 ex_py3(eap);
3180# endif
3181}
3182
3183/*
3184 * ":pyxdo"
3185 */
3186 void
3187ex_pyxdo(exarg_T *eap)
3188{
3189# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3190 init_pyxversion();
3191 if (p_pyx == 2)
3192 ex_pydo(eap);
3193 else
3194 ex_py3do(eap);
3195# elif defined(FEAT_PYTHON)
3196 ex_pydo(eap);
3197# elif defined(FEAT_PYTHON3)
3198 ex_py3do(eap);
3199# endif
3200}
3201
3202#endif
3203
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204/*
3205 * ":source {fname}"
3206 */
3207 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003208ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209{
3210#ifdef FEAT_BROWSE
3211 if (cmdmod.browse)
3212 {
3213 char_u *fname = NULL;
3214
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003215 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02003216 NULL, NULL,
3217 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003218 if (fname != NULL)
3219 {
3220 cmd_source(fname, eap);
3221 vim_free(fname);
3222 }
3223 }
3224 else
3225#endif
3226 cmd_source(eap->arg, eap);
3227}
3228
3229 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003230cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231{
3232 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003233 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003236 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003237 * Need to execute the commands directly. This is required at least
3238 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239 * - ":g" command busy
3240 * - after ":argdo", ":windo" or ":bufdo"
3241 * - another command follows
3242 * - inside a loop
3243 */
3244 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3245#ifdef FEAT_EVAL
3246 || eap->cstack->cs_idx >= 0
3247#endif
3248 );
3249
3250 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003251 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003252 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253}
3254
3255/*
3256 * ":source" and associated commands.
3257 */
3258/*
3259 * Structure used to store info for each sourced file.
3260 * It is shared between do_source() and getsourceline().
3261 * This is required, because it needs to be handed to do_cmdline() and
3262 * sourcing can be done recursively.
3263 */
3264struct source_cookie
3265{
3266 FILE *fp; /* opened file for sourcing */
3267 char_u *nextline; /* if not NULL: line that was read ahead */
3268 int finished; /* ":finish" used */
Bram Moolenaar00590742019-02-15 21:06:09 +01003269#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003270 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3271 int error; /* TRUE if LF found after CR-LF */
3272#endif
3273#ifdef FEAT_EVAL
3274 linenr_T breakpoint; /* next line with breakpoint or zero */
3275 char_u *fname; /* name of sourced file */
3276 int dbg_tick; /* debug_tick when breakpoint was set */
3277 int level; /* top nesting level of sourced file */
3278#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279 vimconv_T conv; /* type of conversion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280};
3281
3282#ifdef FEAT_EVAL
3283/*
3284 * Return the address holding the next breakpoint line for a source cookie.
3285 */
3286 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003287source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288{
3289 return &((struct source_cookie *)cookie)->breakpoint;
3290}
3291
3292/*
3293 * Return the address holding the debug tick for a source cookie.
3294 */
3295 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003296source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297{
3298 return &((struct source_cookie *)cookie)->dbg_tick;
3299}
3300
3301/*
3302 * Return the nesting level for a source cookie.
3303 */
3304 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003305source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306{
3307 return ((struct source_cookie *)cookie)->level;
3308}
3309#endif
3310
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003311static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312
Bram Moolenaar4f974752019-02-17 17:44:42 +01003313#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003314# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315/*
3316 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003317 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318 */
3319 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003320fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003322# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003323 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3324# else
3325 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003326# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327
3328 if (fd_tmp == -1)
3329 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003330
3331# ifdef HAVE_FD_CLOEXEC
3332 {
3333 int fdflags = fcntl(fd_tmp, F_GETFD);
3334 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003335 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003336 }
3337# endif
3338
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 return fdopen(fd_tmp, READBIN);
3340}
3341#endif
3342
3343
3344/*
3345 * do_source: Read the file "fname" and execute its lines as EX commands.
3346 *
3347 * This function may be called recursively!
3348 *
3349 * return FAIL if file could not be opened, OK otherwise
3350 */
3351 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003352do_source(
3353 char_u *fname,
3354 int check_other, /* check for .vimrc and _vimrc */
3355 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356{
3357 struct source_cookie cookie;
3358 char_u *save_sourcing_name;
3359 linenr_T save_sourcing_lnum;
3360 char_u *p;
3361 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003362 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 int retval = FAIL;
3364#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003365 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003367 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003368 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003369 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003370 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003372 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 int stat_ok;
3374# endif
3375#endif
3376#ifdef STARTUPTIME
3377 struct timeval tv_rel;
3378 struct timeval tv_start;
3379#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003380#ifdef FEAT_PROFILE
3381 proftime_T wait_start;
3382#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003383 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003386 if (p == NULL)
3387 return retval;
3388 fname_exp = fix_fname(p);
3389 vim_free(p);
3390 if (fname_exp == NULL)
3391 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 if (mch_isdir(fname_exp))
3393 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003394 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 goto theend;
3396 }
3397
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003398 /* Apply SourceCmd autocommands, they should get the file and source it. */
3399 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3400 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3401 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003402 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003403#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003404 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003405#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003406 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003407#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003408 if (retval == OK)
3409 // Apply SourcePost autocommands.
3410 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
3411 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003412 goto theend;
3413 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003414
3415 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003416 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003417
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003418#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3420#else
3421 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3422#endif
3423 if (cookie.fp == NULL && check_other)
3424 {
3425 /*
3426 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3427 * and ".exrc" by "_exrc" or vice versa.
3428 */
3429 p = gettail(fname_exp);
3430 if ((*p == '.' || *p == '_')
3431 && (STRICMP(p + 1, "vimrc") == 0
3432 || STRICMP(p + 1, "gvimrc") == 0
3433 || STRICMP(p + 1, "exrc") == 0))
3434 {
3435 if (*p == '_')
3436 *p = '.';
3437 else
3438 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003439#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3441#else
3442 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3443#endif
3444 }
3445 }
3446
3447 if (cookie.fp == NULL)
3448 {
3449 if (p_verbose > 0)
3450 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003451 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003453 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003455 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003456 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003457 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458 }
3459 goto theend;
3460 }
3461
3462 /*
3463 * The file exists.
3464 * - In verbose mode, give a message.
3465 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3466 */
3467 if (p_verbose > 1)
3468 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003469 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003471 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003473 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003474 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003475 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003477 if (is_vimrc == DOSO_VIMRC)
3478 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3479 else if (is_vimrc == DOSO_GVIMRC)
3480 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003481
3482#ifdef USE_CRNL
3483 /* If no automatic file format: Set default to CR-NL. */
3484 if (*p_ffs == NUL)
3485 cookie.fileformat = EOL_DOS;
3486 else
3487 cookie.fileformat = EOL_UNKNOWN;
3488 cookie.error = FALSE;
3489#endif
3490
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 cookie.nextline = NULL;
3492 cookie.finished = FALSE;
3493
3494#ifdef FEAT_EVAL
3495 /*
3496 * Check if this script has a breakpoint.
3497 */
3498 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3499 cookie.fname = fname_exp;
3500 cookie.dbg_tick = debug_tick;
3501
3502 cookie.level = ex_nesting_level;
3503#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504
3505 /*
3506 * Keep the sourcing name/lnum, for recursive calls.
3507 */
3508 save_sourcing_name = sourcing_name;
3509 sourcing_name = fname_exp;
3510 save_sourcing_lnum = sourcing_lnum;
3511 sourcing_lnum = 0;
3512
3513#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003514 if (time_fd != NULL)
3515 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516#endif
3517
3518#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003519# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003520 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003521 prof_child_enter(&wait_start); /* entering a child now */
3522# endif
3523
3524 /* Don't use local function variables, if called from a function.
3525 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003526 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003527
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003528 save_current_sctx = current_sctx;
3529 current_sctx.sc_lnum = 0;
3530 current_sctx.sc_version = 1;
3531
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003532 // Check if this script was sourced before to finds its SID.
3533 // If it's new, generate a new SID.
3534 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003535 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536# ifdef UNIX
3537 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3538# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003539 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
3540 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003541 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003542 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003543 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544 && (
3545# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003546 /* Compare dev/ino when possible, it catches symbolic
3547 * links. Also compare file names, the inode may change
3548 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003549 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003550 && (si->sn_dev == st.st_dev
3551 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003553 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003555 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003556 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003558 current_sctx.sc_sid = ++last_current_SID;
3559 if (ga_grow(&script_items,
3560 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003561 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003562 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003563 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003564 ++script_items.ga_len;
3565 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3566# ifdef FEAT_PROFILE
3567 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003568# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003570 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003571 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01003572 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00003573# ifdef UNIX
3574 if (stat_ok)
3575 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003576 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003577 si->sn_dev = st.st_dev;
3578 si->sn_ino = st.st_ino;
3579 }
3580 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003581 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003582# endif
3583
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003585 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 }
3587
Bram Moolenaar05159a02005-02-26 23:04:13 +00003588# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003589 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003590 {
3591 int forceit;
3592
3593 /* Check if we do profiling for this script. */
3594 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3595 {
3596 script_do_profile(si);
3597 si->sn_pr_force = forceit;
3598 }
3599 if (si->sn_prof_on)
3600 {
3601 ++si->sn_pr_count;
3602 profile_start(&si->sn_pr_start);
3603 profile_zero(&si->sn_pr_children);
3604 }
3605 }
3606# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607#endif
3608
Bram Moolenaar67435d92017-10-19 21:04:37 +02003609 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3610
3611 /* Read the first line so we can check for a UTF-8 BOM. */
3612 firstline = getsourceline(0, (void *)&cookie, 0);
3613 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3614 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3615 {
3616 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3617 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3618 p = string_convert(&cookie.conv, firstline + 3, NULL);
3619 if (p == NULL)
3620 p = vim_strsave(firstline + 3);
3621 if (p != NULL)
3622 {
3623 vim_free(firstline);
3624 firstline = p;
3625 }
3626 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02003627
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628 /*
3629 * Call do_cmdline, which will call getsourceline() to get the lines.
3630 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003631 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003632 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003634
3635#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003636 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003637 {
3638 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003639 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003640 if (si->sn_prof_on)
3641 {
3642 profile_end(&si->sn_pr_start);
3643 profile_sub_wait(&wait_start, &si->sn_pr_start);
3644 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003645 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3646 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003647 }
3648 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649#endif
3650
3651 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003652 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653 sourcing_name = save_sourcing_name;
3654 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655 if (p_verbose > 1)
3656 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003657 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003658 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003660 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003661 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662 }
3663#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003664 if (time_fd != NULL)
3665 {
3666 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3667 time_msg((char *)IObuff, &tv_start);
3668 time_pop(&tv_rel);
3669 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670#endif
3671
Bram Moolenaar2b618522019-01-12 13:26:03 +01003672 if (!got_int)
3673 trigger_source_post = TRUE;
3674
Bram Moolenaar071d4272004-06-13 20:20:40 +00003675#ifdef FEAT_EVAL
3676 /*
3677 * After a "finish" in debug mode, need to break at first command of next
3678 * sourced file.
3679 */
3680 if (save_debug_break_level > ex_nesting_level
3681 && debug_break_level == ex_nesting_level)
3682 ++debug_break_level;
3683#endif
3684
Bram Moolenaar05159a02005-02-26 23:04:13 +00003685#ifdef FEAT_EVAL
3686almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003687 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003688 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003689# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003690 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003691 prof_child_exit(&wait_start); /* leaving a child now */
3692# endif
3693#endif
3694 fclose(cookie.fp);
3695 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003696 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003697 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003698
Bram Moolenaar2b618522019-01-12 13:26:03 +01003699 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003700 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003701
Bram Moolenaar071d4272004-06-13 20:20:40 +00003702theend:
3703 vim_free(fname_exp);
3704 return retval;
3705}
3706
3707#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003708
Bram Moolenaar071d4272004-06-13 20:20:40 +00003709/*
3710 * ":scriptnames"
3711 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003713ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714{
3715 int i;
3716
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003717 if (eap->addr_count > 0)
3718 {
3719 // :script {scriptId}: edit the script
3720 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003721 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003722 else
3723 {
3724 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3725 do_exedit(eap, NULL);
3726 }
3727 return;
3728 }
3729
Bram Moolenaar05159a02005-02-26 23:04:13 +00003730 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3731 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003732 {
3733 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3734 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003735 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003736 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737}
3738
3739# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3740/*
3741 * Fix slashes in the list of script names for 'shellslash'.
3742 */
3743 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003744scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745{
3746 int i;
3747
Bram Moolenaar05159a02005-02-26 23:04:13 +00003748 for (i = 1; i <= script_items.ga_len; ++i)
3749 if (SCRIPT_ITEM(i).sn_name != NULL)
3750 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751}
3752# endif
3753
3754/*
3755 * Get a pointer to a script name. Used for ":verbose set".
3756 */
3757 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003758get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003759{
3760 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003761 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003763 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003765 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003766 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003767 return (char_u *)_("environment variable");
3768 if (id == SID_ERROR)
3769 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003770 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003772
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003773# if defined(EXITFREE) || defined(PROTO)
3774 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003775free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003776{
3777 int i;
3778
3779 for (i = script_items.ga_len; i > 0; --i)
3780 vim_free(SCRIPT_ITEM(i).sn_name);
3781 ga_clear(&script_items);
3782}
3783# endif
3784
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785#endif
3786
Bram Moolenaar071d4272004-06-13 20:20:40 +00003787/*
3788 * Get one full line from a sourced file.
3789 * Called by do_cmdline() when it's called from do_source().
3790 *
3791 * Return a pointer to the line in allocated memory.
3792 * Return NULL for end-of-file or some error.
3793 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003795getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796{
3797 struct source_cookie *sp = (struct source_cookie *)cookie;
3798 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003799 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800
3801#ifdef FEAT_EVAL
3802 /* If breakpoints have been added/deleted need to check for it. */
3803 if (sp->dbg_tick < debug_tick)
3804 {
3805 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3806 sp->dbg_tick = debug_tick;
3807 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003808# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003809 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003810 script_line_end();
3811# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812#endif
3813 /*
3814 * Get current line. If there is a read-ahead line, use it, otherwise get
3815 * one now.
3816 */
3817 if (sp->finished)
3818 line = NULL;
3819 else if (sp->nextline == NULL)
3820 line = get_one_sourceline(sp);
3821 else
3822 {
3823 line = sp->nextline;
3824 sp->nextline = NULL;
3825 ++sourcing_lnum;
3826 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003827#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003828 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003829 script_line_start();
3830#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831
3832 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3833 * contain the 'C' flag. */
3834 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3835 {
3836 /* compensate for the one line read-ahead */
3837 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003838
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003839 // Get the next line and concatenate it when it starts with a
3840 // backslash. We always need to read the next line, keep it in
3841 // sp->nextline.
3842 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003843 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003844 if (sp->nextline != NULL
3845 && (*(p = skipwhite(sp->nextline)) == '\\'
3846 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003848 garray_T ga;
3849
Bram Moolenaarb549a732012-02-22 18:29:33 +01003850 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003851 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003852 if (*p == '\\')
3853 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003854 for (;;)
3855 {
3856 vim_free(sp->nextline);
3857 sp->nextline = get_one_sourceline(sp);
3858 if (sp->nextline == NULL)
3859 break;
3860 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003861 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003862 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003863 // Adjust the growsize to the current length to speed up
3864 // concatenating many lines.
3865 if (ga.ga_len > 400)
3866 {
3867 if (ga.ga_len > 8000)
3868 ga.ga_growsize = 8000;
3869 else
3870 ga.ga_growsize = ga.ga_len;
3871 }
3872 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003873 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003874 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3875 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003876 }
3877 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003878 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003879 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880 }
3881 }
3882
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3884 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003885 char_u *s;
3886
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887 /* Convert the encoding of the script line. */
3888 s = string_convert(&sp->conv, line, NULL);
3889 if (s != NULL)
3890 {
3891 vim_free(line);
3892 line = s;
3893 }
3894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895
3896#ifdef FEAT_EVAL
3897 /* Did we encounter a breakpoint? */
3898 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3899 {
3900 dbg_breakpoint(sp->fname, sourcing_lnum);
3901 /* Find next breakpoint. */
3902 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3903 sp->dbg_tick = debug_tick;
3904 }
3905#endif
3906
3907 return line;
3908}
3909
3910 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003911get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912{
3913 garray_T ga;
3914 int len;
3915 int c;
3916 char_u *buf;
3917#ifdef USE_CRNL
3918 int has_cr; /* CR-LF found */
3919#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 int have_read = FALSE;
3921
3922 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003923 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003924
3925 /*
3926 * Loop until there is a finished line (or end-of-file).
3927 */
3928 sourcing_lnum++;
3929 for (;;)
3930 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003931 /* make room to read at least 120 (more) characters */
3932 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 break;
3934 buf = (char_u *)ga.ga_data;
3935
Bram Moolenaar00590742019-02-15 21:06:09 +01003936 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003937 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003938 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003939 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940#ifdef USE_CRNL
3941 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3942 * CTRL-Z by its own, or after a NL. */
3943 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3944 && sp->fileformat == EOL_DOS
3945 && buf[len - 1] == Ctrl_Z)
3946 {
3947 buf[len - 1] = NUL;
3948 break;
3949 }
3950#endif
3951
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953 ga.ga_len = len;
3954
3955 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003956 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003957 continue;
3958
3959 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3960 {
3961#ifdef USE_CRNL
3962 has_cr = (len >= 2 && buf[len - 2] == '\r');
3963 if (sp->fileformat == EOL_UNKNOWN)
3964 {
3965 if (has_cr)
3966 sp->fileformat = EOL_DOS;
3967 else
3968 sp->fileformat = EOL_UNIX;
3969 }
3970
3971 if (sp->fileformat == EOL_DOS)
3972 {
3973 if (has_cr) /* replace trailing CR */
3974 {
3975 buf[len - 2] = '\n';
3976 --len;
3977 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978 }
3979 else /* lines like ":map xx yy^M" will have failed */
3980 {
3981 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003982 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003983 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003984 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003985 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003986 sp->error = TRUE;
3987 sp->fileformat = EOL_UNIX;
3988 }
3989 }
3990#endif
3991 /* The '\n' is escaped if there is an odd number of ^V's just
3992 * before it, first set "c" just before the 'V's and then check
3993 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3994 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3995 ;
3996 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3997 {
3998 sourcing_lnum++;
3999 continue;
4000 }
4001
4002 buf[len - 1] = NUL; /* remove the NL */
4003 }
4004
4005 /*
4006 * Check for ^C here now and then, so recursive :so can be broken.
4007 */
4008 line_breakcheck();
4009 break;
4010 }
4011
4012 if (have_read)
4013 return (char_u *)ga.ga_data;
4014
4015 vim_free(ga.ga_data);
4016 return NULL;
4017}
4018
Bram Moolenaar05159a02005-02-26 23:04:13 +00004019#if defined(FEAT_PROFILE) || defined(PROTO)
4020/*
4021 * Called when starting to read a script line.
4022 * "sourcing_lnum" must be correct!
4023 * When skipping lines it may not actually be executed, but we won't find out
4024 * until later and we need to store the time now.
4025 */
4026 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004027script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004028{
4029 scriptitem_T *si;
4030 sn_prl_T *pp;
4031
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004032 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004033 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004034 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004035 if (si->sn_prof_on && sourcing_lnum >= 1)
4036 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004037 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004038 * here isn't counted. */
Bram Moolenaar67435d92017-10-19 21:04:37 +02004039 (void)ga_grow(&si->sn_prl_ga,
4040 (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004041 si->sn_prl_idx = sourcing_lnum - 1;
4042 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4043 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4044 {
4045 /* Zero counters for a line that was not used before. */
4046 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4047 pp->snp_count = 0;
4048 profile_zero(&pp->sn_prl_total);
4049 profile_zero(&pp->sn_prl_self);
4050 ++si->sn_prl_ga.ga_len;
4051 }
4052 si->sn_prl_execed = FALSE;
4053 profile_start(&si->sn_prl_start);
4054 profile_zero(&si->sn_prl_children);
4055 profile_get_wait(&si->sn_prl_wait);
4056 }
4057}
4058
4059/*
4060 * Called when actually executing a function line.
4061 */
4062 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004063script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004064{
4065 scriptitem_T *si;
4066
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004067 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004068 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004069 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004070 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4071 si->sn_prl_execed = TRUE;
4072}
4073
4074/*
Bram Moolenaar67435d92017-10-19 21:04:37 +02004075 * Called when done with a script line.
Bram Moolenaar05159a02005-02-26 23:04:13 +00004076 */
4077 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004078script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004079{
4080 scriptitem_T *si;
4081 sn_prl_T *pp;
4082
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004083 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004084 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004085 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004086 if (si->sn_prof_on && si->sn_prl_idx >= 0
4087 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4088 {
4089 if (si->sn_prl_execed)
4090 {
4091 pp = &PRL_ITEM(si, si->sn_prl_idx);
4092 ++pp->snp_count;
4093 profile_end(&si->sn_prl_start);
4094 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004095 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004096 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4097 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004098 }
4099 si->sn_prl_idx = -1;
4100 }
4101}
4102#endif
4103
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104/*
4105 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004107 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004108ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004109{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110 struct source_cookie *sp;
4111 char_u *name;
4112
4113 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4114 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004115 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116 return;
4117 }
4118
4119 if (*eap->arg != NUL)
4120 {
4121 name = enc_canonize(eap->arg);
4122 if (name == NULL) /* out of memory */
4123 return;
4124 }
4125 else
4126 name = eap->arg;
4127
4128 /* Setup for conversion from the specified encoding to 'encoding'. */
4129 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4130 convert_setup(&sp->conv, name, p_enc);
4131
4132 if (name != eap->arg)
4133 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134}
4135
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004136/*
4137 * ":scriptversion": Set Vim script version for a sourced script.
4138 */
4139 void
4140ex_scriptversion(exarg_T *eap UNUSED)
4141{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004142#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004143 int nr;
4144
4145 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4146 {
4147 emsg(_("E984: :scriptversion used outside of a sourced file"));
4148 return;
4149 }
4150
4151 nr = getdigits(&eap->arg);
4152 if (nr == 0 || *eap->arg != NUL)
4153 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02004154 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004155 semsg(_("E999: scriptversion not supported: %d"), nr);
4156 else
4157 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004158#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004159}
4160
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161#if defined(FEAT_EVAL) || defined(PROTO)
4162/*
4163 * ":finish": Mark a sourced file as finished.
4164 */
4165 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004166ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167{
4168 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4169 do_finish(eap, FALSE);
4170 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004171 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172}
4173
4174/*
4175 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4176 * Also called for a pending finish at the ":endtry" or after returning from
4177 * an extra do_cmdline(). "reanimate" is used in the latter case.
4178 */
4179 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004180do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181{
4182 int idx;
4183
4184 if (reanimate)
4185 ((struct source_cookie *)getline_cookie(eap->getline,
4186 eap->cookie))->finished = FALSE;
4187
4188 /*
4189 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4190 * not in its finally clause (which then is to be executed next) is found.
4191 * In this case, make the ":finish" pending for execution at the ":endtry".
4192 * Otherwise, finish normally.
4193 */
4194 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4195 if (idx >= 0)
4196 {
4197 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4198 report_make_pending(CSTP_FINISH, NULL);
4199 }
4200 else
4201 ((struct source_cookie *)getline_cookie(eap->getline,
4202 eap->cookie))->finished = TRUE;
4203}
4204
4205
4206/*
4207 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4208 * message for missing ":endif".
4209 * Return FALSE when not sourcing a file.
4210 */
4211 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004212source_finished(
4213 char_u *(*fgetline)(int, void *, int),
4214 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004215{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004216 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004217 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004218 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219}
4220#endif
4221
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222/*
4223 * ":checktime [buffer]"
4224 */
4225 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004226ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227{
4228 buf_T *buf;
4229 int save_no_check_timestamps = no_check_timestamps;
4230
4231 no_check_timestamps = 0;
4232 if (eap->addr_count == 0) /* default is all buffers */
4233 check_timestamps(FALSE);
4234 else
4235 {
4236 buf = buflist_findnr((int)eap->line2);
4237 if (buf != NULL) /* cannot happen? */
4238 (void)buf_check_timestamp(buf, FALSE);
4239 }
4240 no_check_timestamps = save_no_check_timestamps;
4241}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4244 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004245# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004246 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004247get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004249 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004251 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004252 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253
Bram Moolenaar4f974752019-02-17 17:44:42 +01004254# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255 if (loc != NULL)
4256 {
4257 char_u *p;
4258
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004259 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4260 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 p = vim_strchr(loc, '=');
4262 if (p != NULL)
4263 {
4264 loc = ++p;
4265 while (*p != NUL) /* remove trailing newline */
4266 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004267 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268 {
4269 *p = NUL;
4270 break;
4271 }
4272 ++p;
4273 }
4274 }
4275 }
4276# endif
4277
4278 return loc;
4279}
4280#endif
4281
4282
Bram Moolenaar4f974752019-02-17 17:44:42 +01004283#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004284/*
4285 * On MS-Windows locale names are strings like "German_Germany.1252", but
4286 * gettext expects "de". Try to translate one into another here for a few
4287 * supported languages.
4288 */
4289 static char_u *
4290gettext_lang(char_u *name)
4291{
4292 int i;
4293 static char *(mtable[]) = {
4294 "afrikaans", "af",
4295 "czech", "cs",
4296 "dutch", "nl",
4297 "german", "de",
4298 "english_united kingdom", "en_GB",
4299 "spanish", "es",
4300 "french", "fr",
4301 "italian", "it",
4302 "japanese", "ja",
4303 "korean", "ko",
4304 "norwegian", "no",
4305 "polish", "pl",
4306 "russian", "ru",
4307 "slovak", "sk",
4308 "swedish", "sv",
4309 "ukrainian", "uk",
4310 "chinese_china", "zh_CN",
4311 "chinese_taiwan", "zh_TW",
4312 NULL};
4313
4314 for (i = 0; mtable[i] != NULL; i += 2)
4315 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004316 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004317 return name;
4318}
4319#endif
4320
4321#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4322/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01004323 * Return TRUE when "lang" starts with a valid language name.
4324 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
4325 */
4326 static int
4327is_valid_mess_lang(char_u *lang)
4328{
4329 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
4330}
4331
4332/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333 * Obtain the current messages language. Used to set the default for
4334 * 'helplang'. May return NULL or an empty string.
4335 */
4336 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004337get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338{
4339 char_u *p;
4340
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004341# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004343 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344# else
4345 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004346 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4347 * and LC_MONETARY may be set differently for a Japanese working in the
4348 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004349 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350# endif
4351# else
4352 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004353 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354 {
4355 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004356 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 p = mch_getenv((char_u *)"LANG");
4358 }
4359# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004360# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 p = gettext_lang(p);
4362# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01004363 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364}
4365#endif
4366
Bram Moolenaardef9e822004-12-31 20:58:58 +00004367/* Complicated #if; matches with where get_mess_env() is used below. */
4368#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4369 && defined(LC_MESSAGES))) \
4370 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00004371 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372/*
4373 * Get the language used for messages from the environment.
4374 */
4375 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004376get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377{
4378 char_u *p;
4379
4380 p = mch_getenv((char_u *)"LC_ALL");
4381 if (p == NULL || *p == NUL)
4382 {
4383 p = mch_getenv((char_u *)"LC_MESSAGES");
4384 if (p == NULL || *p == NUL)
4385 {
4386 p = mch_getenv((char_u *)"LANG");
4387 if (p != NULL && VIM_ISDIGIT(*p))
4388 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004389# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004391 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392# endif
4393 }
4394 }
4395 return p;
4396}
4397#endif
4398
4399#if defined(FEAT_EVAL) || defined(PROTO)
4400
4401/*
4402 * Set the "v:lang" variable according to the current locale setting.
4403 * Also do "v:lc_time"and "v:ctype".
4404 */
4405 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004406set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407{
4408 char_u *loc;
4409
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004410# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004411 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412# else
4413 /* setlocale() not supported: use the default value */
4414 loc = (char_u *)"C";
4415# endif
4416 set_vim_var_string(VV_CTYPE, loc, -1);
4417
4418 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4419 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004420# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004421 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422# else
4423 loc = get_mess_env();
4424# endif
4425 set_vim_var_string(VV_LANG, loc, -1);
4426
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004427# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004428 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429# endif
4430 set_vim_var_string(VV_LC_TIME, loc, -1);
4431}
4432#endif
4433
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01004434#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435/*
4436 * ":language": Set the language (locale).
4437 */
4438 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004439ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440{
4441 char *loc;
4442 char_u *p;
4443 char_u *name;
4444 int what = LC_ALL;
4445 char *whatstr = "";
4446#ifdef LC_MESSAGES
4447# define VIM_LC_MESSAGES LC_MESSAGES
4448#else
4449# define VIM_LC_MESSAGES 6789
4450#endif
4451
4452 name = eap->arg;
4453
4454 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4455 * Allow abbreviation, but require at least 3 characters to avoid
4456 * confusion with a two letter language name "me" or "ct". */
4457 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004458 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004459 {
4460 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4461 {
4462 what = VIM_LC_MESSAGES;
4463 name = skipwhite(p);
4464 whatstr = "messages ";
4465 }
4466 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4467 {
4468 what = LC_CTYPE;
4469 name = skipwhite(p);
4470 whatstr = "ctype ";
4471 }
4472 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4473 {
4474 what = LC_TIME;
4475 name = skipwhite(p);
4476 whatstr = "time ";
4477 }
4478 }
4479
4480 if (*name == NUL)
4481 {
4482#ifndef LC_MESSAGES
4483 if (what == VIM_LC_MESSAGES)
4484 p = get_mess_env();
4485 else
4486#endif
4487 p = (char_u *)setlocale(what, NULL);
4488 if (p == NULL || *p == NUL)
4489 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004490 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 }
4492 else
4493 {
4494#ifndef LC_MESSAGES
4495 if (what == VIM_LC_MESSAGES)
4496 loc = "";
4497 else
4498#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004499 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004500 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004501#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4502 /* Make sure strtod() uses a decimal point, not a comma. */
4503 setlocale(LC_NUMERIC, "C");
4504#endif
4505 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004507 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 else
4509 {
4510#ifdef HAVE_NL_MSG_CAT_CNTR
4511 /* Need to do this for GNU gettext, otherwise cached translations
4512 * will be used again. */
4513 extern int _nl_msg_cat_cntr;
4514
4515 ++_nl_msg_cat_cntr;
4516#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004517 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4519
4520 if (what != LC_TIME)
4521 {
4522 /* Tell gettext() what to translate to. It apparently doesn't
4523 * use the currently effective locale. Also do this when
4524 * FEAT_GETTEXT isn't defined, so that shell commands use this
4525 * value. */
4526 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004527 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004529
4530 /* Clear $LANGUAGE because GNU gettext uses it. */
4531 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01004532# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004533 /* Apparently MS-Windows printf() may cause a crash when
4534 * we give it 8-bit text while it's expecting text in the
4535 * current locale. This call avoids that. */
4536 setlocale(LC_CTYPE, "C");
4537# endif
4538 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 if (what != LC_CTYPE)
4540 {
4541 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01004542#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 mname = gettext_lang(name);
4544#else
4545 mname = name;
4546#endif
4547 vim_setenv((char_u *)"LC_MESSAGES", mname);
4548#ifdef FEAT_MULTI_LANG
4549 set_helplang_default(mname);
4550#endif
4551 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552 }
4553
4554# ifdef FEAT_EVAL
4555 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4556 set_lang_var();
4557# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004558# ifdef FEAT_TITLE
4559 maketitle();
4560# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561 }
4562 }
4563}
4564
4565# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004566
4567static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004568
Bram Moolenaar4f974752019-02-17 17:44:42 +01004569# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004570static int did_init_locales = FALSE;
4571
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004572/* Return an array of strings for all available locales + NULL for the
4573 * last element. Return NULL in case of error. */
4574 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004575find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004576{
4577 garray_T locales_ga;
4578 char_u *loc;
4579
4580 /* Find all available locales by running command "locale -a". If this
4581 * doesn't work we won't have completion. */
4582 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004583 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004584 if (locale_a == NULL)
4585 return NULL;
4586 ga_init2(&locales_ga, sizeof(char_u *), 20);
4587
4588 /* Transform locale_a string where each locale is separated by "\n"
4589 * into an array of locale strings. */
4590 loc = (char_u *)strtok((char *)locale_a, "\n");
4591
4592 while (loc != NULL)
4593 {
4594 if (ga_grow(&locales_ga, 1) == FAIL)
4595 break;
4596 loc = vim_strsave(loc);
4597 if (loc == NULL)
4598 break;
4599
4600 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4601 loc = (char_u *)strtok(NULL, "\n");
4602 }
4603 vim_free(locale_a);
4604 if (ga_grow(&locales_ga, 1) == FAIL)
4605 {
4606 ga_clear(&locales_ga);
4607 return NULL;
4608 }
4609 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4610 return (char_u **)locales_ga.ga_data;
4611}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004612# endif
4613
4614/*
4615 * Lazy initialization of all available locales.
4616 */
4617 static void
4618init_locales(void)
4619{
Bram Moolenaar4f974752019-02-17 17:44:42 +01004620# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004621 if (!did_init_locales)
4622 {
4623 did_init_locales = TRUE;
4624 locales = find_locales();
4625 }
4626# endif
4627}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004628
4629# if defined(EXITFREE) || defined(PROTO)
4630 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004631free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004632{
4633 int i;
4634 if (locales != NULL)
4635 {
4636 for (i = 0; locales[i] != NULL; i++)
4637 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004638 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004639 }
4640}
4641# endif
4642
Bram Moolenaar071d4272004-06-13 20:20:40 +00004643/*
4644 * Function given to ExpandGeneric() to obtain the possible arguments of the
4645 * ":language" command.
4646 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004648get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649{
4650 if (idx == 0)
4651 return (char_u *)"messages";
4652 if (idx == 1)
4653 return (char_u *)"ctype";
4654 if (idx == 2)
4655 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004656
4657 init_locales();
4658 if (locales == NULL)
4659 return NULL;
4660 return locales[idx - 3];
4661}
4662
4663/*
4664 * Function given to ExpandGeneric() to obtain the available locales.
4665 */
4666 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004667get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004668{
4669 init_locales();
4670 if (locales == NULL)
4671 return NULL;
4672 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673}
4674# endif
4675
4676#endif