blob: 59452032bd92375dd71a3926db445cff5b0dbe20 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar433f7c82006-03-21 21:29:36 +000069# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +000070/*
71 * Store the current time in "tm".
72 */
73 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010074profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +000075{
Bram Moolenaar4f974752019-02-17 17:44:42 +010076# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000077 QueryPerformanceCounter(tm);
78# else
Bram Moolenaar05159a02005-02-26 23:04:13 +000079 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000080# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +000081}
82
83/*
84 * Compute the elapsed time from "tm" till now and store in "tm".
85 */
86 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010087profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +000088{
89 proftime_T now;
90
Bram Moolenaar4f974752019-02-17 17:44:42 +010091# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000092 QueryPerformanceCounter(&now);
93 tm->QuadPart = now.QuadPart - tm->QuadPart;
94# else
Bram Moolenaar05159a02005-02-26 23:04:13 +000095 gettimeofday(&now, NULL);
96 tm->tv_usec = now.tv_usec - tm->tv_usec;
97 tm->tv_sec = now.tv_sec - tm->tv_sec;
98 if (tm->tv_usec < 0)
99 {
100 tm->tv_usec += 1000000;
101 --tm->tv_sec;
102 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000103# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000104}
105
106/*
107 * Subtract the time "tm2" from "tm".
108 */
109 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100110profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000111{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100112# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000113 tm->QuadPart -= tm2->QuadPart;
114# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000115 tm->tv_usec -= tm2->tv_usec;
116 tm->tv_sec -= tm2->tv_sec;
117 if (tm->tv_usec < 0)
118 {
119 tm->tv_usec += 1000000;
120 --tm->tv_sec;
121 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000122# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000123}
124
125/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000126 * Return a string that represents the time in "tm".
127 * Uses a static buffer!
128 */
129 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100130profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000131{
132 static char buf[50];
133
Bram Moolenaar4f974752019-02-17 17:44:42 +0100134# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000135 LARGE_INTEGER fr;
136
137 QueryPerformanceFrequency(&fr);
138 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
139# else
140 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000141# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000142 return buf;
143}
144
Bram Moolenaar79c2c882016-02-07 21:19:28 +0100145# if defined(FEAT_FLOAT) || defined(PROTO)
146/*
147 * Return a float that represents the time in "tm".
148 */
149 float_T
150profile_float(proftime_T *tm)
151{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100152# ifdef MSWIN
Bram Moolenaar79c2c882016-02-07 21:19:28 +0100153 LARGE_INTEGER fr;
154
155 QueryPerformanceFrequency(&fr);
156 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
157# else
158 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
159# endif
160}
161# endif
162
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000163/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000164 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000165 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000166 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100167profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +0000168{
169 if (msec <= 0) /* no limit */
170 profile_zero(tm);
171 else
172 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100173# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +0000174 LARGE_INTEGER fr;
175
176 QueryPerformanceCounter(tm);
177 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000178 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000179# else
180 long usec;
181
182 gettimeofday(tm, NULL);
183 usec = (long)tm->tv_usec + (long)msec * 1000;
184 tm->tv_usec = usec % 1000000L;
185 tm->tv_sec += usec / 1000000L;
186# endif
187 }
188}
189
190/*
191 * Return TRUE if the current time is past "tm".
192 */
193 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100194profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +0000195{
196 proftime_T now;
197
Bram Moolenaar4f974752019-02-17 17:44:42 +0100198# ifdef MSWIN
Bram Moolenaar76929292008-01-06 19:07:36 +0000199 if (tm->QuadPart == 0) /* timer was not set */
200 return FALSE;
201 QueryPerformanceCounter(&now);
202 return (now.QuadPart > tm->QuadPart);
203# else
204 if (tm->tv_sec == 0) /* timer was not set */
205 return FALSE;
206 gettimeofday(&now, NULL);
207 return (now.tv_sec > tm->tv_sec
208 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
209# endif
210}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000211
212/*
213 * Set the time in "tm" to zero.
214 */
215 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100216profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000217{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100218# ifdef MSWIN
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000219 tm->QuadPart = 0;
220# else
221 tm->tv_usec = 0;
222 tm->tv_sec = 0;
223# endif
224}
225
Bram Moolenaar76929292008-01-06 19:07:36 +0000226# endif /* FEAT_PROFILE || FEAT_RELTIME */
227
Bram Moolenaar975b5272016-03-15 23:10:59 +0100228# if defined(FEAT_TIMERS) || defined(PROTO)
229static timer_T *first_timer = NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200230static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100231
Bram Moolenaar2f106582019-05-08 21:59:25 +0200232/*
233 * Return time left until "due". Negative if past "due".
234 */
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200235 long
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100236proftime_time_left(proftime_T *due, proftime_T *now)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200237{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100238# ifdef MSWIN
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200239 LARGE_INTEGER fr;
240
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100241 if (now->QuadPart > due->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200242 return 0;
243 QueryPerformanceFrequency(&fr);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100244 return (long)(((double)(due->QuadPart - now->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200245 / (double)fr.QuadPart) * 1000);
246# else
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100247 if (now->tv_sec > due->tv_sec)
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200248 return 0;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100249 return (due->tv_sec - now->tv_sec) * 1000
250 + (due->tv_usec - now->tv_usec) / 1000;
Bram Moolenaara8e93d62017-09-18 21:50:47 +0200251# endif
252}
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200253
Bram Moolenaar975b5272016-03-15 23:10:59 +0100254/*
255 * Insert a timer in the list of timers.
256 */
257 static void
258insert_timer(timer_T *timer)
259{
260 timer->tr_next = first_timer;
261 timer->tr_prev = NULL;
262 if (first_timer != NULL)
263 first_timer->tr_prev = timer;
264 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +0200265 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100266}
267
268/*
269 * Take a timer out of the list of timers.
270 */
271 static void
272remove_timer(timer_T *timer)
273{
274 if (timer->tr_prev == NULL)
275 first_timer = timer->tr_next;
276 else
277 timer->tr_prev->tr_next = timer->tr_next;
278 if (timer->tr_next != NULL)
279 timer->tr_next->tr_prev = timer->tr_prev;
280}
281
282 static void
283free_timer(timer_T *timer)
284{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200285 free_callback(timer->tr_callback, timer->tr_partial);
286 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100287}
288
289/*
290 * Create a timer and return it. NULL if out of memory.
291 * Caller should set the callback.
292 */
293 timer_T *
294create_timer(long msec, int repeat)
295{
296 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
Bram Moolenaaree39ef02016-09-10 19:17:42 +0200297 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100298
299 if (timer == NULL)
300 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +0200301 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200302 /* Overflow! Might cause duplicates... */
303 last_timer_id = 0;
304 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100305 insert_timer(timer);
306 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100307 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200308 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100309
310 profile_setlimit(msec, &timer->tr_due);
311 return timer;
312}
313
314/*
315 * Invoke the callback of "timer".
316 */
317 static void
318timer_callback(timer_T *timer)
319{
320 typval_T rettv;
321 int dummy;
322 typval_T argv[2];
323
324 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200325 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100326 argv[1].v_type = VAR_UNKNOWN;
327
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200328 call_func(timer->tr_callback, -1,
Bram Moolenaardf48fb42016-07-22 21:50:18 +0200329 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +0100330 timer->tr_partial, NULL);
331 clear_tv(&rettv);
332}
333
334/*
335 * Call timers that are due.
336 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200337 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100338 */
339 long
Bram Moolenaarcf089462016-06-12 21:18:43 +0200340check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100341{
342 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200343 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100344 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +0100345 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100346 proftime_T now;
347 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200348 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200349 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100350
Bram Moolenaarc577d812017-07-08 22:37:34 +0200351 /* Don't run any timers while exiting or dealing with an error. */
352 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200353 return next_due;
354
Bram Moolenaar75537a92016-09-05 22:45:28 +0200355 profile_start(&now);
356 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100357 {
Bram Moolenaar75537a92016-09-05 22:45:28 +0200358 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200359
Bram Moolenaar75537a92016-09-05 22:45:28 +0200360 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
361 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100362 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200363 if (this_due <= 1)
364 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200365 /* Save and restore a lot of flags, because the timer fires while
366 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200367 int save_timer_busy = timer_busy;
368 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200369 int save_did_emsg = did_emsg;
370 int save_called_emsg = called_emsg;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200371 int save_must_redraw = must_redraw;
Bram Moolenaare723c422017-09-06 23:40:10 +0200372 int save_trylevel = trylevel;
373 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200374 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare723c422017-09-06 23:40:10 +0200375 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200376 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200377
Bram Moolenaare723c422017-09-06 23:40:10 +0200378 /* Create a scope for running the timer callback, ignoring most of
379 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200380 timer_busy = timer_busy > 0 || vgetc_busy > 0;
381 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +0200382 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200383 did_emsg = FALSE;
384 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200385 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +0200386 trylevel = 0;
387 did_throw = FALSE;
388 current_exception = NULL;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200389 save_vimvars(&vvsave);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200390 timer->tr_firing = TRUE;
391 timer_callback(timer);
392 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200393
Bram Moolenaar75537a92016-09-05 22:45:28 +0200394 timer_next = timer->tr_next;
395 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200396 timer_busy = save_timer_busy;
397 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200398 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200399 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200400 did_emsg = save_did_emsg;
401 called_emsg = save_called_emsg;
402 trylevel = save_trylevel;
403 did_throw = save_did_throw;
404 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200405 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200406 if (must_redraw != 0)
407 need_update_screen = TRUE;
408 must_redraw = must_redraw > save_must_redraw
409 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200410 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200411
412 /* Only fire the timer again if it repeats and stop_timer() wasn't
413 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200414 if (timer->tr_repeat != 0 && timer->tr_id != -1
415 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200416 {
417 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100418 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200419 if (this_due < 1)
420 this_due = 1;
421 if (timer->tr_repeat > 0)
422 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100423 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200424 else
425 {
426 this_due = -1;
427 remove_timer(timer);
428 free_timer(timer);
429 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100430 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200431 if (this_due > 0 && (next_due == -1 || next_due > this_due))
432 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100433 }
434
435 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200436 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100437
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100438#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100439 if (bevalexpr_due_set)
440 {
441 this_due = proftime_time_left(&bevalexpr_due, &now);
442 if (this_due <= 1)
443 {
444 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100445 if (balloonEval == NULL)
446 {
Bram Moolenaarca4b6132018-06-28 12:05:11 +0200447 balloonEval = (BalloonEval *)alloc_clear(sizeof(BalloonEval));
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100448 balloonEvalForTerm = TRUE;
449 }
450 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200451 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100452 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200453 setcursor();
454 out_flush();
455 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100456 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200457 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100458 next_due = this_due;
459 }
460#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200461#ifdef FEAT_TERMINAL
462 /* Some terminal windows may need their buffer updated. */
463 next_due = term_check_timers(next_due, &now);
464#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100465
Bram Moolenaar75537a92016-09-05 22:45:28 +0200466 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100467}
468
469/*
470 * Find a timer by ID. Returns NULL if not found;
471 */
472 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200473find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100474{
475 timer_T *timer;
476
Bram Moolenaar75537a92016-09-05 22:45:28 +0200477 if (id >= 0)
478 {
479 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
480 if (timer->tr_id == id)
481 return timer;
482 }
483 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100484}
485
486
487/*
488 * Stop a timer and delete it.
489 */
490 void
491stop_timer(timer_T *timer)
492{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200493 if (timer->tr_firing)
494 /* Free the timer after the callback returns. */
495 timer->tr_id = -1;
496 else
497 {
498 remove_timer(timer);
499 free_timer(timer);
500 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100501}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200502
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200503 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200504stop_all_timers(void)
505{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200506 timer_T *timer;
507 timer_T *timer_next;
508
509 for (timer = first_timer; timer != NULL; timer = timer_next)
510 {
511 timer_next = timer->tr_next;
512 stop_timer(timer);
513 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200514}
515
516 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200517add_timer_info(typval_T *rettv, timer_T *timer)
518{
519 list_T *list = rettv->vval.v_list;
520 dict_T *dict = dict_alloc();
521 dictitem_T *di;
522 long remaining;
523 proftime_T now;
524
525 if (dict == NULL)
526 return;
527 list_append_dict(list, dict);
528
Bram Moolenaare0be1672018-07-08 16:50:37 +0200529 dict_add_number(dict, "id", timer->tr_id);
530 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200531
532 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100533 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200534 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200535
Bram Moolenaare0be1672018-07-08 16:50:37 +0200536 dict_add_number(dict, "repeat",
537 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
538 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200539
540 di = dictitem_alloc((char_u *)"callback");
541 if (di != NULL)
542 {
543 if (dict_add(dict, di) == FAIL)
544 vim_free(di);
545 else if (timer->tr_partial != NULL)
546 {
547 di->di_tv.v_type = VAR_PARTIAL;
548 di->di_tv.vval.v_partial = timer->tr_partial;
549 ++timer->tr_partial->pt_refcount;
550 }
551 else
552 {
553 di->di_tv.v_type = VAR_FUNC;
554 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
555 }
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200556 }
557}
558
559 void
560add_timer_info_all(typval_T *rettv)
561{
562 timer_T *timer;
563
564 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200565 if (timer->tr_id != -1)
566 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200567}
568
Bram Moolenaare3188e22016-05-31 21:13:04 +0200569/*
570 * Mark references in partials of timers.
571 */
572 int
573set_ref_in_timer(int copyID)
574{
575 int abort = FALSE;
576 timer_T *timer;
577 typval_T tv;
578
579 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
580 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200581 if (timer->tr_partial != NULL)
582 {
583 tv.v_type = VAR_PARTIAL;
584 tv.vval.v_partial = timer->tr_partial;
585 }
586 else
587 {
588 tv.v_type = VAR_FUNC;
589 tv.vval.v_string = timer->tr_callback;
590 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200591 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
592 }
593 return abort;
594}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200595
596# if defined(EXITFREE) || defined(PROTO)
597 void
598timer_free_all()
599{
600 timer_T *timer;
601
602 while (first_timer != NULL)
603 {
604 timer = first_timer;
605 remove_timer(timer);
606 free_timer(timer);
607 }
608}
609# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100610# endif
611
Bram Moolenaar113e1072019-01-20 15:30:40 +0100612#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) && defined(FEAT_PROFILE)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200613# if defined(HAVE_MATH_H)
614# include <math.h>
615# endif
616
617/*
618 * Divide the time "tm" by "count" and store in "tm2".
619 */
620 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100621profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200622{
623 if (count == 0)
624 profile_zero(tm2);
625 else
626 {
Bram Moolenaar4f974752019-02-17 17:44:42 +0100627# ifdef MSWIN
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200628 tm2->QuadPart = tm->QuadPart / count;
629# else
630 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
631
632 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200633 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200634# endif
635 }
636}
637#endif
638
Bram Moolenaar76929292008-01-06 19:07:36 +0000639# if defined(FEAT_PROFILE) || defined(PROTO)
640/*
641 * Functions for profiling.
642 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100643static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +0000644static proftime_T prof_wait_time;
645
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000646/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000647 * Add the time "tm2" to "tm".
648 */
649 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100650profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000651{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100652# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000653 tm->QuadPart += tm2->QuadPart;
654# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000655 tm->tv_usec += tm2->tv_usec;
656 tm->tv_sec += tm2->tv_sec;
657 if (tm->tv_usec >= 1000000)
658 {
659 tm->tv_usec -= 1000000;
660 ++tm->tv_sec;
661 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000662# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000663}
664
665/*
Bram Moolenaar1056d982006-03-09 22:37:52 +0000666 * Add the "self" time from the total time and the children's time.
667 */
668 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100669profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +0000670{
671 /* Check that the result won't be negative. Can happen with recursive
672 * calls. */
Bram Moolenaar4f974752019-02-17 17:44:42 +0100673#ifdef MSWIN
Bram Moolenaar1056d982006-03-09 22:37:52 +0000674 if (total->QuadPart <= children->QuadPart)
675 return;
676#else
677 if (total->tv_sec < children->tv_sec
678 || (total->tv_sec == children->tv_sec
679 && total->tv_usec <= children->tv_usec))
680 return;
681#endif
682 profile_add(self, total);
683 profile_sub(self, children);
684}
685
686/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000687 * Get the current waittime.
688 */
689 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100690profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000691{
692 *tm = prof_wait_time;
693}
694
695/*
696 * Subtract the passed waittime since "tm" from "tma".
697 */
698 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100699profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000700{
701 proftime_T tm3 = prof_wait_time;
702
703 profile_sub(&tm3, tm);
704 profile_sub(tma, &tm3);
705}
706
707/*
708 * Return TRUE if "tm1" and "tm2" are equal.
709 */
710 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100711profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000712{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100713# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000714 return (tm1->QuadPart == tm2->QuadPart);
715# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000716 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000717# endif
718}
719
720/*
721 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
722 */
723 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100724profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000725{
Bram Moolenaar4f974752019-02-17 17:44:42 +0100726# ifdef MSWIN
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000727 return (int)(tm2->QuadPart - tm1->QuadPart);
728# else
729 if (tm1->tv_sec == tm2->tv_sec)
730 return tm2->tv_usec - tm1->tv_usec;
731 return tm2->tv_sec - tm1->tv_sec;
732# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000733}
734
Bram Moolenaar05159a02005-02-26 23:04:13 +0000735static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000736static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000737
738/*
739 * ":profile cmd args"
740 */
741 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100742ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000743{
744 char_u *e;
745 int len;
746
747 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000748 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000749 e = skipwhite(e);
750
751 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
752 {
753 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +0200754 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000755 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000756 profile_zero(&prof_wait_time);
757 set_vim_var_nr(VV_PROFILING, 1L);
758 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000759 else if (do_profiling == PROF_NONE)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100760 emsg(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +0000761 else if (STRCMP(eap->arg, "pause") == 0)
762 {
763 if (do_profiling == PROF_YES)
764 profile_start(&pause_time);
765 do_profiling = PROF_PAUSED;
766 }
767 else if (STRCMP(eap->arg, "continue") == 0)
768 {
769 if (do_profiling == PROF_PAUSED)
770 {
771 profile_end(&pause_time);
772 profile_add(&prof_wait_time, &pause_time);
773 }
774 do_profiling = PROF_YES;
775 }
Bram Moolenaar05159a02005-02-26 23:04:13 +0000776 else
777 {
778 /* The rest is similar to ":breakadd". */
779 ex_breakadd(eap);
780 }
781}
782
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100783/* Command line expansion for :profile. */
784static enum
785{
786 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +0100787 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100788} pexpand_what;
789
790static char *pexpand_cmds[] = {
791 "start",
792#define PROFCMD_START 0
793 "pause",
794#define PROFCMD_PAUSE 1
795 "continue",
796#define PROFCMD_CONTINUE 2
797 "func",
798#define PROFCMD_FUNC 3
799 "file",
800#define PROFCMD_FILE 4
801 NULL
802#define PROFCMD_LAST 5
803};
804
805/*
806 * Function given to ExpandGeneric() to obtain the profile command
807 * specific expansion.
808 */
809 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100810get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100811{
812 switch (pexpand_what)
813 {
814 case PEXP_SUBCMD:
815 return (char_u *)pexpand_cmds[idx];
816 /* case PEXP_FUNC: TODO */
817 default:
818 return NULL;
819 }
820}
821
822/*
823 * Handle command line completion for :profile command.
824 */
825 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100826set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100827{
828 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100829
830 /* Default: expand subcommands. */
831 xp->xp_context = EXPAND_PROFILE;
832 pexpand_what = PEXP_SUBCMD;
833 xp->xp_pattern = arg;
834
835 end_subcmd = skiptowhite(arg);
836 if (*end_subcmd == NUL)
837 return;
838
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +0100839 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +0100840 {
841 xp->xp_context = EXPAND_FILES;
842 xp->xp_pattern = skipwhite(end_subcmd);
843 return;
844 }
845
846 /* TODO: expand function names after "func" */
847 xp->xp_context = EXPAND_NOTHING;
848}
849
Bram Moolenaar05159a02005-02-26 23:04:13 +0000850/*
851 * Dump the profiling info.
852 */
853 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100854profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000855{
856 FILE *fd;
857
858 if (profile_fname != NULL)
859 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000860 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861 if (fd == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100862 semsg(_(e_notopen), profile_fname);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000863 else
864 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000865 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000866 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000867 fclose(fd);
868 }
869 }
870}
871
872/*
873 * Start profiling script "fp".
874 */
875 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100876script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000877{
878 si->sn_pr_count = 0;
879 profile_zero(&si->sn_pr_total);
880 profile_zero(&si->sn_pr_self);
881
882 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
883 si->sn_prl_idx = -1;
884 si->sn_prof_on = TRUE;
885 si->sn_pr_nest = 0;
886}
887
888/*
Bram Moolenaar67435d92017-10-19 21:04:37 +0200889 * Save time when starting to invoke another script or function.
Bram Moolenaar05159a02005-02-26 23:04:13 +0000890 */
891 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100892script_prof_save(
893 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000894{
895 scriptitem_T *si;
896
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200897 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000898 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200899 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000900 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
901 profile_start(&si->sn_pr_child);
902 }
903 profile_get_wait(tm);
904}
905
906/*
907 * Count time spent in children after invoking another script or function.
908 */
909 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100910script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000911{
912 scriptitem_T *si;
913
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200914 if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000915 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200916 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000917 if (si->sn_prof_on && --si->sn_pr_nest == 0)
918 {
919 profile_end(&si->sn_pr_child);
920 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
921 profile_add(&si->sn_pr_children, &si->sn_pr_child);
922 profile_add(&si->sn_prl_children, &si->sn_pr_child);
923 }
924 }
925}
926
927static proftime_T inchar_time;
928
929/*
930 * Called when starting to wait for the user to type a character.
931 */
932 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100933prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000934{
935 profile_start(&inchar_time);
936}
937
938/*
939 * Called when finished waiting for the user to type a character.
940 */
941 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100942prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943{
944 profile_end(&inchar_time);
945 profile_add(&prof_wait_time, &inchar_time);
946}
947
948/*
949 * Dump the profiling results for all scripts in file "fd".
950 */
951 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100952script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000953{
954 int id;
955 scriptitem_T *si;
956 int i;
957 FILE *sfd;
958 sn_prl_T *pp;
959
960 for (id = 1; id <= script_items.ga_len; ++id)
961 {
962 si = &SCRIPT_ITEM(id);
963 if (si->sn_prof_on)
964 {
965 fprintf(fd, "SCRIPT %s\n", si->sn_name);
966 if (si->sn_pr_count == 1)
967 fprintf(fd, "Sourced 1 time\n");
968 else
969 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
970 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
971 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
972 fprintf(fd, "\n");
973 fprintf(fd, "count total (s) self (s)\n");
974
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000975 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 if (sfd == NULL)
977 fprintf(fd, "Cannot open file!\n");
978 else
979 {
Bram Moolenaar67435d92017-10-19 21:04:37 +0200980 /* Keep going till the end of file, so that trailing
981 * continuation lines are listed. */
982 for (i = 0; ; ++i)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000983 {
984 if (vim_fgets(IObuff, IOSIZE, sfd))
985 break;
Bram Moolenaarac112f02017-12-05 16:46:28 +0100986 /* When a line has been truncated, append NL, taking care
987 * of multi-byte characters . */
988 if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
989 {
990 int n = IOSIZE - 2;
Bram Moolenaar13505972019-01-24 15:04:48 +0100991
Bram Moolenaarac112f02017-12-05 16:46:28 +0100992 if (enc_utf8)
993 {
994 /* Move to the first byte of this char.
995 * utf_head_off() doesn't work, because it checks
996 * for a truncated character. */
997 while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
998 --n;
999 }
1000 else if (has_mbyte)
1001 n -= mb_head_off(IObuff, IObuff + n);
Bram Moolenaarac112f02017-12-05 16:46:28 +01001002 IObuff[n] = NL;
1003 IObuff[n + 1] = NUL;
1004 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02001005 if (i < si->sn_prl_ga.ga_len
1006 && (pp = &PRL_ITEM(si, i))->snp_count > 0)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001007 {
1008 fprintf(fd, "%5d ", pp->snp_count);
1009 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1010 fprintf(fd, " ");
1011 else
1012 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1013 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1014 }
1015 else
1016 fprintf(fd, " ");
1017 fprintf(fd, "%s", IObuff);
1018 }
1019 fclose(sfd);
1020 }
1021 fprintf(fd, "\n");
1022 }
1023 }
1024}
1025
1026/*
1027 * Return TRUE when a function defined in the current script should be
1028 * profiled.
1029 */
1030 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001031prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001032{
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02001033 if (current_sctx.sc_sid > 0)
1034 return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001035 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001036}
1037
1038# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039#endif
1040
1041/*
1042 * If 'autowrite' option set, try to write the file.
1043 * Careful: autocommands may make "buf" invalid!
1044 *
1045 * return FAIL for failure, OK otherwise
1046 */
1047 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001048autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001050 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001051 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001052
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 if (!(p_aw || p_awa) || !p_write
1054#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001055 /* never autowrite a "nofile" or "nowrite" buffer */
1056 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001057#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001058 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001059 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001060 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001061 r = buf_write_all(buf, forceit);
1062
1063 /* Writing may succeed but the buffer still changed, e.g., when there is a
1064 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001065 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001066 r = FAIL;
1067 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068}
1069
1070/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001071 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001072 */
1073 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001074autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075{
1076 buf_T *buf;
1077
1078 if (!(p_aw || p_awa) || !p_write)
1079 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001080 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +02001081 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001083 bufref_T bufref;
1084
1085 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001086
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001088
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001090 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 }
1093}
1094
1095/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001096 * Return TRUE if buffer was changed and cannot be abandoned.
1097 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001100check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001102 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001103 bufref_T bufref;
1104
1105 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001106
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 if ( !forceit
1108 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001109 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1110 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 {
1112#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1113 if ((p_confirm || cmdmod.confirm) && p_write)
1114 {
1115 buf_T *buf2;
1116 int count = 0;
1117
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001118 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001119 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001120 if (bufIsChanged(buf2)
1121 && (buf2->b_ffname != NULL
1122# ifdef FEAT_BROWSE
1123 || cmdmod.browse
1124# endif
1125 ))
1126 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001127 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 /* Autocommand deleted buffer, oops! It's not changed now. */
1129 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001130
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001132
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001133 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134 /* Autocommand deleted buffer, oops! It's not changed now. */
1135 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001136 return bufIsChanged(buf);
1137 }
1138#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001139 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +02001140 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001141 else
Bram Moolenaar7a760922018-02-19 23:10:02 +01001142 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143 return TRUE;
1144 }
1145 return FALSE;
1146}
1147
1148#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1149
1150#if defined(FEAT_BROWSE) || defined(PROTO)
1151/*
1152 * When wanting to write a file without a file name, ask the user for a name.
1153 */
1154 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001155browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001156{
1157 if (buf->b_fname == NULL)
1158 {
1159 char_u *fname;
1160
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001161 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1162 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 if (fname != NULL)
1164 {
1165 if (setfname(buf, fname, NULL, TRUE) == OK)
1166 buf->b_flags |= BF_NOTEDITED;
1167 vim_free(fname);
1168 }
1169 }
1170}
1171#endif
1172
1173/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001174 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175 * Must check 'write' option first!
1176 */
1177 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001178dialog_changed(
1179 buf_T *buf,
1180 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001182 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001183 int ret;
1184 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001185 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +02001187 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188 if (checkall)
1189 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1190 else
1191 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1192
Bram Moolenaar4ca41532019-05-09 21:48:37 +02001193 // Init ea pseudo-structure, this is needed for the check_overwrite()
1194 // function.
1195 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +02001196
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197 if (ret == VIM_YES)
1198 {
1199#ifdef FEAT_BROWSE
1200 /* May get file name, when there is none */
1201 browse_save_fname(buf);
1202#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001203 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1204 buf->b_fname, buf->b_ffname, FALSE) == OK)
1205 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 (void)buf_write_all(buf, FALSE);
1207 }
1208 else if (ret == VIM_NO)
1209 {
1210 unchanged(buf, TRUE);
1211 }
1212 else if (ret == VIM_ALL)
1213 {
1214 /*
1215 * Write all modified files that can be written.
1216 * Skip readonly buffers, these need to be confirmed
1217 * individually.
1218 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001219 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220 {
1221 if (bufIsChanged(buf2)
1222 && (buf2->b_ffname != NULL
1223#ifdef FEAT_BROWSE
1224 || cmdmod.browse
1225#endif
1226 )
1227 && !buf2->b_p_ro)
1228 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001229 bufref_T bufref;
1230
1231 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001232#ifdef FEAT_BROWSE
1233 /* May get file name, when there is none */
1234 browse_save_fname(buf2);
1235#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001236 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1237 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1238 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001239 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001240
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001242 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 }
1245 }
1246 }
1247 else if (ret == VIM_DISCARDALL)
1248 {
1249 /*
1250 * mark all buffers as unchanged
1251 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001252 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253 unchanged(buf2, TRUE);
1254 }
1255}
1256#endif
1257
1258/*
1259 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1260 * hidden, autowriting it or unloading it.
1261 */
1262 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001263can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264{
Bram Moolenaareb44a682017-08-03 22:44:55 +02001265 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 || !bufIsChanged(buf)
1267 || buf->b_nwindows > 1
1268 || autowrite(buf, forceit) == OK
1269 || forceit);
1270}
1271
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001272/*
1273 * Add a buffer number to "bufnrs", unless it's already there.
1274 */
1275 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001276add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001277{
1278 int i;
1279
1280 for (i = 0; i < *bufnump; ++i)
1281 if (bufnrs[i] == nr)
1282 return;
1283 bufnrs[*bufnump] = nr;
1284 *bufnump = *bufnump + 1;
1285}
1286
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287/*
1288 * Return TRUE if any buffer was changed and cannot be abandoned.
1289 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001290 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +01001291 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292 */
1293 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001294check_changed_any(
1295 int hidden, /* Only check hidden buffers */
1296 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001298 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299 buf_T *buf;
1300 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001301 int i;
1302 int bufnum = 0;
1303 int bufcount = 0;
1304 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001305 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001308 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001309 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001310 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001312 if (bufcount == 0)
1313 return FALSE;
1314
1315 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1316 if (bufnrs == NULL)
1317 return FALSE;
1318
1319 /* curbuf */
1320 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001321
1322 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001323 FOR_ALL_WINDOWS(wp)
1324 if (wp->w_buffer != curbuf)
1325 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1326
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001327 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +02001328 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001329 if (tp != curtab)
1330 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1331 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001332
1333 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +02001334 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001335 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1336
1337 for (i = 0; i < bufnum; ++i)
1338 {
1339 buf = buflist_findnr(bufnrs[i]);
1340 if (buf == NULL)
1341 continue;
1342 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1343 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001344 bufref_T bufref;
1345
1346 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001347#ifdef FEAT_TERMINAL
1348 if (term_job_running(buf->b_term))
1349 {
1350 if (term_try_stop_job(buf) == FAIL)
1351 break;
1352 }
1353 else
1354#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001355 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02001356 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001357 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1358 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001359 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001360 break; /* didn't save - still changes */
1361 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362 }
1363
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001364 if (i >= bufnum)
1365 goto theend;
1366
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +01001367 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001368 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369 exiting = FALSE;
1370#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1371 /*
1372 * When ":confirm" used, don't give an error message.
1373 */
1374 if (!(p_confirm || cmdmod.confirm))
1375#endif
1376 {
1377 /* There must be a wait_return for this message, do_buffer()
1378 * may cause a redraw. But wait_return() is a no-op when vgetc()
1379 * is busy (Quit used from window menu), then make sure we don't
1380 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001381 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001382 {
1383 msg_row = cmdline_row;
1384 msg_col = 0;
1385 msg_didout = FALSE;
1386 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001387 if (
1388#ifdef FEAT_TERMINAL
1389 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001390 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +02001391 buf->b_fname)
1392 :
1393#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001394 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001395 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001396 {
1397 save = no_wait_return;
1398 no_wait_return = FALSE;
1399 wait_return(FALSE);
1400 no_wait_return = save;
1401 }
1402 }
1403
Bram Moolenaar071d4272004-06-13 20:20:40 +00001404 /* Try to find a window that contains the buffer. */
1405 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001406 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407 if (wp->w_buffer == buf)
1408 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001409 bufref_T bufref;
1410
1411 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001412
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001413 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001414
Bram Moolenaarbdace832019-03-02 10:13:42 +01001415 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001416 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001417 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001418 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001420buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001421
1422 /* Open the changed buffer in the current window. */
1423 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001424 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001426theend:
1427 vim_free(bufnrs);
1428 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429}
1430
1431/*
1432 * return FAIL if there is no file name, OK if there is one
1433 * give error message for FAIL
1434 */
1435 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001436check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001437{
1438 if (curbuf->b_ffname == NULL)
1439 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001440 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001441 return FAIL;
1442 }
1443 return OK;
1444}
1445
1446/*
1447 * flush the contents of a buffer, unless it has no file name
1448 *
1449 * return FAIL for failure, OK otherwise
1450 */
1451 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001452buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453{
1454 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456
1457 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1458 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1459 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001461 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01001462 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +01001463 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001464 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465 return retval;
1466}
1467
1468/*
1469 * Code to handle the argument list.
1470 */
1471
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001472static int do_arglist(char_u *str, int what, int after, int will_edit);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001473static void alist_check_arg_idx(void);
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001474static void alist_add_list(int count, char_u **files, int after, int will_edit);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001475#define AL_SET 1
1476#define AL_ADD 2
1477#define AL_DEL 3
1478
Bram Moolenaar071d4272004-06-13 20:20:40 +00001479/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001480 * Isolate one argument, taking backticks.
1481 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001482 * Return a pointer to the start of the next argument.
1483 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001484 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001485do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486{
1487 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 int inbacktick;
1489
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 inbacktick = FALSE;
1491 for (p = str; *str; ++str)
1492 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001493 /* When the backslash is used for escaping the special meaning of a
1494 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495 if (rem_backslash(str))
1496 {
1497 *p++ = *str++;
1498 *p++ = *str;
1499 }
1500 else
1501 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001502 /* An item ends at a space not in backticks */
1503 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001505 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001507 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508 }
1509 }
1510 str = skipwhite(str);
1511 *p = NUL;
1512
1513 return str;
1514}
1515
Bram Moolenaar86b68352004-12-27 21:59:20 +00001516/*
1517 * Separate the arguments in "str" and return a list of pointers in the
1518 * growarray "gap".
1519 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001520 static int
1521get_arglist(garray_T *gap, char_u *str, int escaped)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001522{
1523 ga_init2(gap, (int)sizeof(char_u *), 20);
1524 while (*str != NUL)
1525 {
1526 if (ga_grow(gap, 1) == FAIL)
1527 {
1528 ga_clear(gap);
1529 return FAIL;
1530 }
1531 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1532
Bram Moolenaar398ee732017-08-03 14:29:14 +02001533 /* If str is escaped, don't handle backslashes or spaces */
1534 if (!escaped)
1535 return OK;
1536
Bram Moolenaar86b68352004-12-27 21:59:20 +00001537 /* Isolate one argument, change it in-place, put a NUL after it. */
1538 str = do_one_arg(str);
1539 }
1540 return OK;
1541}
1542
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001543#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001544/*
1545 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001546 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001547 * Return FAIL or OK.
1548 */
1549 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001550get_arglist_exp(
1551 char_u *str,
1552 int *fcountp,
1553 char_u ***fnamesp,
1554 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001555{
1556 garray_T ga;
1557 int i;
1558
Bram Moolenaar398ee732017-08-03 14:29:14 +02001559 if (get_arglist(&ga, str, TRUE) == FAIL)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001560 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001561 if (wig == TRUE)
1562 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1563 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1564 else
1565 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1566 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1567
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001568 ga_clear(&ga);
1569 return i;
1570}
1571#endif
1572
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573/*
1574 * Redefine the argument list.
1575 */
1576 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001577set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001578{
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001579 do_arglist(str, AL_SET, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581
1582/*
1583 * "what" == AL_SET: Redefine the argument list to 'str'.
1584 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1585 * "what" == AL_DEL: remove files in 'str' from the argument list.
1586 *
1587 * Return FAIL for failure, OK otherwise.
1588 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001590do_arglist(
1591 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01001592 int what,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001593 int after UNUSED, // 0 means before first one
1594 int will_edit) // will edit added argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00001595{
1596 garray_T new_ga;
1597 int exp_count;
1598 char_u **exp_files;
1599 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600 char_u *p;
1601 int match;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001602 int arg_escaped = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603
1604 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001605 * Set default argument for ":argadd" command.
1606 */
1607 if (what == AL_ADD && *str == NUL)
1608 {
1609 if (curbuf->b_ffname == NULL)
1610 return FAIL;
1611 str = curbuf->b_fname;
Bram Moolenaar398ee732017-08-03 14:29:14 +02001612 arg_escaped = FALSE;
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01001613 }
1614
1615 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 * Collect all file name arguments in "new_ga".
1617 */
Bram Moolenaar398ee732017-08-03 14:29:14 +02001618 if (get_arglist(&new_ga, str, arg_escaped) == FAIL)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001619 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 if (what == AL_DEL)
1622 {
1623 regmatch_T regmatch;
1624 int didone;
1625
1626 /*
1627 * Delete the items: use each item as a regexp and find a match in the
1628 * argument list.
1629 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001630 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001631 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1632 {
1633 p = ((char_u **)new_ga.ga_data)[i];
1634 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1635 if (p == NULL)
1636 break;
1637 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1638 if (regmatch.regprog == NULL)
1639 {
1640 vim_free(p);
1641 break;
1642 }
1643
1644 didone = FALSE;
1645 for (match = 0; match < ARGCOUNT; ++match)
1646 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1647 (colnr_T)0))
1648 {
1649 didone = TRUE;
1650 vim_free(ARGLIST[match].ae_fname);
1651 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1652 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1653 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 if (curwin->w_arg_idx > match)
1655 --curwin->w_arg_idx;
1656 --match;
1657 }
1658
Bram Moolenaar473de612013-06-08 18:19:48 +02001659 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660 vim_free(p);
1661 if (!didone)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001662 semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001663 }
1664 ga_clear(&new_ga);
1665 }
1666 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667 {
1668 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1669 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1670 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01001671 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001673 emsg(_(e_nomatch));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674 return FAIL;
1675 }
1676
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 if (what == AL_ADD)
1678 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001679 alist_add_list(exp_count, exp_files, after, will_edit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680 vim_free(exp_files);
1681 }
1682 else /* what == AL_SET */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001683 alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 }
1685
1686 alist_check_arg_idx();
1687
1688 return OK;
1689}
1690
1691/*
1692 * Check the validity of the arg_idx for each other window.
1693 */
1694 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001695alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001698 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699
Bram Moolenaarf740b292006-02-16 22:11:02 +00001700 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701 if (win->w_alist == curwin->w_alist)
1702 check_arg_idx(win);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703}
1704
1705/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01001706 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001707 * index.
1708 */
1709 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001710editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001711{
1712 return !(win->w_arg_idx >= WARGCOUNT(win)
1713 || (win->w_buffer->b_fnum
1714 != WARGLIST(win)[win->w_arg_idx].ae_fnum
1715 && (win->w_buffer->b_ffname == NULL
1716 || !(fullpathcmp(
1717 alist_name(&WARGLIST(win)[win->w_arg_idx]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001718 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))));
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001719}
1720
1721/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722 * Check if window "win" is editing the w_arg_idx file in its argument list.
1723 */
1724 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001725check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001727 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 {
1729 /* We are not editing the current entry in the argument list.
1730 * Set "arg_had_last" if we are editing the last one. */
1731 win->w_arg_idx_invalid = TRUE;
1732 if (win->w_arg_idx != WARGCOUNT(win) - 1
1733 && arg_had_last == FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 && ALIST(win) == &global_alist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735 && GARGCOUNT > 0
1736 && win->w_arg_idx < GARGCOUNT
1737 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1738 || (win->w_buffer->b_ffname != NULL
1739 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
Bram Moolenaar99499b12019-05-23 21:35:48 +02001740 win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 arg_had_last = TRUE;
1742 }
1743 else
1744 {
1745 /* We are editing the current entry in the argument list.
1746 * Set "arg_had_last" if it's also the last one */
1747 win->w_arg_idx_invalid = FALSE;
1748 if (win->w_arg_idx == WARGCOUNT(win) - 1
Bram Moolenaar4033c552017-09-16 20:54:51 +02001749 && win->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 arg_had_last = TRUE;
1751 }
1752}
1753
1754/*
1755 * ":args", ":argslocal" and ":argsglobal".
1756 */
1757 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001758ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759{
1760 int i;
1761
1762 if (eap->cmdidx != CMD_args)
1763 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 alist_unlink(ALIST(curwin));
1765 if (eap->cmdidx == CMD_argglobal)
1766 ALIST(curwin) = &global_alist;
1767 else /* eap->cmdidx == CMD_arglocal */
1768 alist_new();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001769 }
1770
Bram Moolenaar2ac372c2018-12-28 19:06:47 +01001771 if (*eap->arg != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 {
1773 /*
1774 * ":args file ..": define new argument list, handle like ":next"
1775 * Also for ":argslocal file .." and ":argsglobal file ..".
1776 */
1777 ex_next(eap);
1778 }
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02001779 else if (eap->cmdidx == CMD_args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780 {
1781 /*
1782 * ":args": list arguments.
1783 */
1784 if (ARGCOUNT > 0)
1785 {
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001786 char_u **items = (char_u **)alloc(sizeof(char_u *) * ARGCOUNT);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001787
1788 if (items != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 {
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001790 /* Overwrite the command, for a short list there is no
1791 * scrolling required and no wait_return(). */
1792 gotocmdline(TRUE);
1793
1794 for (i = 0; i < ARGCOUNT; ++i)
Bram Moolenaar405dadb2018-04-20 22:48:58 +02001795 items[i] = alist_name(&ARGLIST[i]);
Bram Moolenaar5d69da42018-04-20 22:01:41 +02001796 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
1797 vim_free(items);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 }
1799 }
1800 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 else if (eap->cmdidx == CMD_arglocal)
1802 {
1803 garray_T *gap = &curwin->w_alist->al_ga;
1804
1805 /*
1806 * ":argslocal": make a local copy of the global argument list.
1807 */
1808 if (ga_grow(gap, GARGCOUNT) == OK)
1809 for (i = 0; i < GARGCOUNT; ++i)
1810 if (GARGLIST[i].ae_fname != NULL)
1811 {
1812 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1813 vim_strsave(GARGLIST[i].ae_fname);
1814 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1815 GARGLIST[i].ae_fnum;
1816 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 }
1818 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819}
1820
1821/*
1822 * ":previous", ":sprevious", ":Next" and ":sNext".
1823 */
1824 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001825ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826{
1827 /* If past the last one already, go to the last one. */
1828 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1829 do_argfile(eap, ARGCOUNT - 1);
1830 else
1831 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1832}
1833
1834/*
1835 * ":rewind", ":first", ":sfirst" and ":srewind".
1836 */
1837 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001838ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839{
1840 do_argfile(eap, 0);
1841}
1842
1843/*
1844 * ":last" and ":slast".
1845 */
1846 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001847ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848{
1849 do_argfile(eap, ARGCOUNT - 1);
1850}
1851
1852/*
1853 * ":argument" and ":sargument".
1854 */
1855 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001856ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857{
1858 int i;
1859
1860 if (eap->addr_count > 0)
1861 i = eap->line2 - 1;
1862 else
1863 i = curwin->w_arg_idx;
1864 do_argfile(eap, i);
1865}
1866
1867/*
1868 * Edit file "argn" of the argument lists.
1869 */
1870 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001871do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872{
1873 int other;
1874 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001875 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876
1877 if (argn < 0 || argn >= ARGCOUNT)
1878 {
1879 if (ARGCOUNT <= 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001880 emsg(_("E163: There is only one file to edit"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881 else if (argn < 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001882 emsg(_("E164: Cannot go before first file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001884 emsg(_("E165: Cannot go beyond last file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885 }
1886 else
1887 {
1888 setpcmark();
1889#ifdef FEAT_GUI
1890 need_mouse_correct = TRUE;
1891#endif
1892
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00001893 /* split window or create new tab page first */
1894 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 {
1896 if (win_split(0, 0) == FAIL)
1897 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001898 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 }
1900 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901 {
1902 /*
1903 * if 'hidden' set, only check for changed file when re-editing
1904 * the same buffer
1905 */
1906 other = TRUE;
Bram Moolenaareb44a682017-08-03 22:44:55 +02001907 if (buf_hide(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 {
1909 p = fix_fname(alist_name(&ARGLIST[argn]));
1910 other = otherfile(p);
1911 vim_free(p);
1912 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02001913 if ((!buf_hide(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001914 && check_changed(curbuf, CCGD_AW
1915 | (other ? 0 : CCGD_MULTWIN)
1916 | (eap->forceit ? CCGD_FORCEIT : 0)
1917 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918 return;
1919 }
1920
1921 curwin->w_arg_idx = argn;
Bram Moolenaar4033c552017-09-16 20:54:51 +02001922 if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923 arg_had_last = TRUE;
1924
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001925 /* Edit the file; always use the last known line number.
1926 * When it fails (e.g. Abort for already edited file) restore the
1927 * argument index. */
1928 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 eap, ECMD_LAST,
Bram Moolenaareb44a682017-08-03 22:44:55 +02001930 (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001931 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001932 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00001934 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 setmark('\'');
1936 }
1937}
1938
1939/*
1940 * ":next", and commands that behave like it.
1941 */
1942 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001943ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944{
1945 int i;
1946
1947 /*
1948 * check for changed buffer now, if this fails the argument list is not
1949 * redefined.
1950 */
Bram Moolenaareb44a682017-08-03 22:44:55 +02001951 if ( buf_hide(curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001953 || !check_changed(curbuf, CCGD_AW
1954 | (eap->forceit ? CCGD_FORCEIT : 0)
1955 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 {
1957 if (*eap->arg != NUL) /* redefine file list */
1958 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001959 if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 return;
1961 i = 0;
1962 }
1963 else
1964 i = curwin->w_arg_idx + (int)eap->line2;
1965 do_argfile(eap, i);
1966 }
1967}
1968
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969/*
1970 * ":argedit"
1971 */
1972 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001973ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974{
Bram Moolenaar90305c62017-07-16 15:31:17 +02001975 int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001976 // Whether curbuf will be reused, curbuf->b_ffname will be set.
1977 int curbuf_is_reusable = curbuf_reusable();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978
Bram Moolenaar32bbd002018-08-31 23:06:22 +02001979 if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL)
Bram Moolenaar90305c62017-07-16 15:31:17 +02001980 return;
1981#ifdef FEAT_TITLE
1982 maketitle();
1983#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984
Bram Moolenaar46a53df2018-04-24 21:58:51 +02001985 if (curwin->w_arg_idx == 0
1986 && (curbuf->b_ml.ml_flags & ML_EMPTY)
1987 && (curbuf->b_ffname == NULL || curbuf_is_reusable))
Bram Moolenaar90305c62017-07-16 15:31:17 +02001988 i = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 /* Edit the argument. */
Bram Moolenaar90305c62017-07-16 15:31:17 +02001990 if (i < ARGCOUNT)
1991 do_argfile(eap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992}
1993
1994/*
1995 * ":argadd"
1996 */
1997 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001998ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999{
2000 do_arglist(eap->arg, AL_ADD,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002001 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1,
2002 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003#ifdef FEAT_TITLE
2004 maketitle();
2005#endif
2006}
2007
2008/*
2009 * ":argdelete"
2010 */
2011 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002012ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013{
2014 int i;
2015 int n;
2016
2017 if (eap->addr_count > 0)
2018 {
2019 /* ":1,4argdel": Delete all arguments in the range. */
2020 if (eap->line2 > ARGCOUNT)
2021 eap->line2 = ARGCOUNT;
2022 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002023 if (*eap->arg != NUL)
2024 /* Can't have both a range and an argument. */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002025 emsg(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002026 else if (n <= 0)
2027 {
2028 /* Don't give an error for ":%argdel" if the list is empty. */
2029 if (eap->line1 != 1 || eap->line2 != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002030 emsg(_(e_invrange));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002031 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002032 else
2033 {
2034 for (i = eap->line1; i <= eap->line2; ++i)
2035 vim_free(ARGLIST[i - 1].ae_fname);
2036 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2037 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2038 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 if (curwin->w_arg_idx >= eap->line2)
2040 curwin->w_arg_idx -= n;
2041 else if (curwin->w_arg_idx > eap->line1)
2042 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002043 if (ARGCOUNT == 0)
2044 curwin->w_arg_idx = 0;
2045 else if (curwin->w_arg_idx >= ARGCOUNT)
2046 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047 }
2048 }
2049 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002050 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 else
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002052 do_arglist(eap->arg, AL_DEL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053#ifdef FEAT_TITLE
2054 maketitle();
2055#endif
2056}
2057
2058/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002059 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 */
2061 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002062ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063{
2064 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002065 win_T *wp;
2066 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +01002067 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002069#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002072 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002073#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002074 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002075 int qf_idx;
2076#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002077
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002078#ifndef FEAT_QUICKFIX
2079 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2080 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2081 {
2082 ex_ni(eap);
2083 return;
2084 }
2085#endif
2086
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002087#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002088 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002089 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2090 * great speed improvement. */
2091 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002093#ifdef FEAT_CLIPBOARD
2094 start_global_changes();
2095#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096
2097 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002098 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +02002099 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002100 || !check_changed(curbuf, CCGD_AW
2101 | (eap->forceit ? CCGD_FORCEIT : 0)
2102 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002105 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002106 wp = firstwin;
2107 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002108 switch (eap->cmdidx)
2109 {
Bram Moolenaara162bc52015-01-07 16:54:21 +01002110 case CMD_windo:
2111 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2112 i++;
2113 break;
2114 case CMD_tabdo:
2115 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2116 i++;
2117 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002118 case CMD_argdo:
2119 i = eap->line1 - 1;
2120 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002121 default:
2122 break;
2123 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 /* set pcmark now */
2125 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002126 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002127 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002128 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002129 || !buf->b_p_bl); buf = buf->b_next)
2130 if (buf->b_fnum > eap->line2)
2131 {
2132 buf = NULL;
2133 break;
2134 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002135 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002136 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002137 }
2138#ifdef FEAT_QUICKFIX
2139 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2140 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2141 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02002142 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002143 if (qf_size <= 0 || eap->line1 > qf_size)
2144 buf = NULL;
2145 else
2146 {
2147 ex_cc(eap);
2148
2149 buf = curbuf;
2150 i = eap->line1 - 1;
2151 if (eap->addr_count <= 0)
2152 /* default is all the quickfix/location list entries */
2153 eap->line2 = qf_size;
2154 }
2155 }
2156#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157 else
2158 setpcmark();
2159 listcmd_busy = TRUE; /* avoids setting pcmark below */
2160
Bram Moolenaare25bb902015-02-27 20:33:37 +01002161 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 {
2163 if (eap->cmdidx == CMD_argdo)
2164 {
2165 /* go to argument "i" */
2166 if (i == ARGCOUNT)
2167 break;
2168 /* Don't call do_argfile() when already there, it will try
2169 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002170 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002171 {
2172 /* Clear 'shm' to avoid that the file message overwrites
2173 * any output from the command. */
2174 p_shm_save = vim_strsave(p_shm);
2175 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002177 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2178 vim_free(p_shm_save);
2179 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180 if (curwin->w_arg_idx != i)
2181 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 else if (eap->cmdidx == CMD_windo)
2184 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002185 /* go to window "wp" */
2186 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002188 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002189 if (curwin != wp)
2190 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002191 wp = curwin->w_next;
2192 }
2193 else if (eap->cmdidx == CMD_tabdo)
2194 {
2195 /* go to window "tp" */
2196 if (!valid_tabpage(tp))
2197 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002198 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002199 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201 else if (eap->cmdidx == CMD_bufdo)
2202 {
2203 /* Remember the number of the next listed buffer, in case
2204 * ":bwipe" is used or autocommands do something strange. */
2205 next_fnum = -1;
2206 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2207 if (buf->b_p_bl)
2208 {
2209 next_fnum = buf->b_fnum;
2210 break;
2211 }
2212 }
2213
Bram Moolenaara162bc52015-01-07 16:54:21 +01002214 ++i;
2215
Bram Moolenaar071d4272004-06-13 20:20:40 +00002216 /* execute the command */
2217 do_cmdline(eap->arg, eap->getline, eap->cookie,
2218 DOCMD_VERBOSE + DOCMD_NOWAIT);
2219
2220 if (eap->cmdidx == CMD_bufdo)
2221 {
2222 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002223 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224 break;
2225 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02002226 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227 if (buf->b_fnum == next_fnum)
2228 break;
2229 if (buf == NULL)
2230 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002231
2232 /* Go to the next buffer. Clear 'shm' to avoid that the file
2233 * message overwrites any output from the command. */
2234 p_shm_save = vim_strsave(p_shm);
2235 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002236 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002237 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2238 vim_free(p_shm_save);
2239
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002240 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 if (curbuf->b_fnum != next_fnum)
2242 break;
2243 }
2244
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002245#ifdef FEAT_QUICKFIX
2246 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2247 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2248 {
2249 if (i >= qf_size || i >= eap->line2)
2250 break;
2251
2252 qf_idx = qf_get_cur_idx(eap);
2253
2254 ex_cnext(eap);
2255
2256 /* If jumping to the next quickfix entry fails, quit here */
2257 if (qf_get_cur_idx(eap) == qf_idx)
2258 break;
2259 }
2260#endif
2261
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 if (eap->cmdidx == CMD_windo)
2263 {
2264 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01002265
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 /* required when 'scrollbind' has been set */
2267 if (curwin->w_p_scb)
2268 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002270
Bram Moolenaara162bc52015-01-07 16:54:21 +01002271 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2272 if (i+1 > eap->line2)
2273 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002274 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2275 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 }
2277 listcmd_busy = FALSE;
2278 }
2279
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002280#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002281 if (save_ei != NULL)
2282 {
2283 au_event_restore(save_ei);
2284 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2285 curbuf->b_fname, TRUE, curbuf);
2286 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002288#ifdef FEAT_CLIPBOARD
2289 end_global_changes();
2290#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291}
2292
2293/*
2294 * Add files[count] to the arglist of the current window after arg "after".
2295 * The file names in files[count] must have been allocated and are taken over.
2296 * Files[] itself is not taken over.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 */
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002298 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002299alist_add_list(
2300 int count,
2301 char_u **files,
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002302 int after, // where to add: 0 = before first one
2303 int will_edit) // will edit adding argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304{
2305 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002306 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307
2308 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2309 {
2310 if (after < 0)
2311 after = 0;
2312 if (after > ARGCOUNT)
2313 after = ARGCOUNT;
2314 if (after < ARGCOUNT)
2315 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2316 (ARGCOUNT - after) * sizeof(aentry_T));
2317 for (i = 0; i < count; ++i)
2318 {
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002319 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
2320
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 ARGLIST[after + i].ae_fname = files[i];
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002322 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 }
2324 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002325 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2326 curwin->w_arg_idx += count;
Bram Moolenaar32bbd002018-08-31 23:06:22 +02002327 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 }
2329
2330 for (i = 0; i < count; ++i)
2331 vim_free(files[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332}
2333
Bram Moolenaarcd43eff2018-03-29 15:55:38 +02002334#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2335/*
2336 * Function given to ExpandGeneric() to obtain the possible arguments of the
2337 * argedit and argdelete commands.
2338 */
2339 char_u *
2340get_arglist_name(expand_T *xp UNUSED, int idx)
2341{
2342 if (idx >= ARGCOUNT)
2343 return NULL;
2344
2345 return alist_name(&ARGLIST[idx]);
2346}
2347#endif
2348
Bram Moolenaar0c72fe42018-03-29 16:04:08 +02002349
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350#ifdef FEAT_EVAL
2351/*
2352 * ":compiler[!] {name}"
2353 */
2354 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002355ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356{
2357 char_u *buf;
2358 char_u *old_cur_comp = NULL;
2359 char_u *p;
2360
2361 if (*eap->arg == NUL)
2362 {
2363 /* List all compiler scripts. */
2364 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2365 /* ) keep the indenter happy... */
2366 }
2367 else
2368 {
2369 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2370 if (buf != NULL)
2371 {
2372 if (eap->forceit)
2373 {
2374 /* ":compiler! {name}" sets global options */
2375 do_cmdline_cmd((char_u *)
2376 "command -nargs=* CompilerSet set <args>");
2377 }
2378 else
2379 {
2380 /* ":compiler! {name}" sets local options.
2381 * To remain backwards compatible "current_compiler" is always
2382 * used. A user's compiler plugin may set it, the distributed
2383 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002384 * "b:current_compiler" and restore "current_compiler".
2385 * Explicitly prepend "g:" to make it work in a function. */
2386 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 if (old_cur_comp != NULL)
2388 old_cur_comp = vim_strsave(old_cur_comp);
2389 do_cmdline_cmd((char_u *)
2390 "command -nargs=* CompilerSet setlocal <args>");
2391 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002392 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002393 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394
2395 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002396 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002397 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 vim_free(buf);
2399
2400 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2401
2402 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002403 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 if (p != NULL)
2405 set_internal_string_var((char_u *)"b:current_compiler", p);
2406
2407 /* Restore "current_compiler" for ":compiler {name}". */
2408 if (!eap->forceit)
2409 {
2410 if (old_cur_comp != NULL)
2411 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002412 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413 old_cur_comp);
2414 vim_free(old_cur_comp);
2415 }
2416 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002417 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418 }
2419 }
2420 }
2421}
2422#endif
2423
2424/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002425 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 */
2427 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002428ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002430 char_u *arg = eap->arg;
2431 char_u *p = skiptowhite(arg);
2432 int len = (int)(p - arg);
2433 int flags = eap->forceit ? DIP_ALL : 0;
2434
2435 if (STRNCMP(arg, "START", len) == 0)
2436 {
2437 flags += DIP_START + DIP_NORTP;
2438 arg = skipwhite(arg + len);
2439 }
2440 else if (STRNCMP(arg, "OPT", len) == 0)
2441 {
2442 flags += DIP_OPT + DIP_NORTP;
2443 arg = skipwhite(arg + len);
2444 }
2445 else if (STRNCMP(arg, "PACK", len) == 0)
2446 {
2447 flags += DIP_START + DIP_OPT + DIP_NORTP;
2448 arg = skipwhite(arg + len);
2449 }
2450 else if (STRNCMP(arg, "ALL", len) == 0)
2451 {
2452 flags += DIP_START + DIP_OPT;
2453 arg = skipwhite(arg + len);
2454 }
2455
2456 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457}
2458
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002460source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002462 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463}
2464
2465/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002466 * Find the file "name" in all directories in "path" and invoke
2467 * "callback(fname, cookie)".
2468 * "name" can contain wildcards.
2469 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2470 * When "flags" has DIP_DIR: find directories instead of files.
2471 * When "flags" has DIP_ERR: give an error message if there is no match.
2472 *
2473 * return FAIL when no file could be sourced, OK otherwise.
2474 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01002475 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002476do_in_path(
2477 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002478 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01002479 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002480 void (*callback)(char_u *fname, void *ck),
2481 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482{
2483 char_u *rtp;
2484 char_u *np;
2485 char_u *buf;
2486 char_u *rtp_copy;
2487 char_u *tail;
2488 int num_files;
2489 char_u **files;
2490 int i;
2491 int did_one = FALSE;
2492#ifdef AMIGA
2493 struct Process *proc = (struct Process *)FindTask(0L);
2494 APTR save_winptr = proc->pr_WindowPtr;
2495
2496 /* Avoid a requester here for a volume that doesn't exist. */
2497 proc->pr_WindowPtr = (APTR)-1L;
2498#endif
2499
2500 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2501 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002502 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 buf = alloc(MAXPATHL);
2504 if (buf != NULL && rtp_copy != NULL)
2505 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002506 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002507 {
2508 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002509 smsg(_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002510 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002511 verbose_leave();
2512 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002513
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514 /* Loop over all entries in 'runtimepath'. */
2515 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01002516 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02002518 size_t buflen;
2519
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520 /* Copy the path from 'runtimepath' to buf[]. */
2521 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02002522 buflen = STRLEN(buf);
2523
2524 /* Skip after or non-after directories. */
2525 if (flags & (DIP_NOAFTER | DIP_AFTER))
2526 {
2527 int is_after = buflen >= 5
2528 && STRCMP(buf + buflen - 5, "after") == 0;
2529
2530 if ((is_after && (flags & DIP_NOAFTER))
2531 || (!is_after && (flags & DIP_AFTER)))
2532 continue;
2533 }
2534
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002535 if (name == NULL)
2536 {
2537 (*callback)(buf, (void *) &cookie);
2538 if (!did_one)
2539 did_one = (cookie == NULL);
2540 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02002541 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002542 {
2543 add_pathsep(buf);
2544 tail = buf + STRLEN(buf);
2545
2546 /* Loop over all patterns in "name" */
2547 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01002548 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002549 {
2550 /* Append the pattern from "name" to buf[]. */
2551 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2552 "\t ");
2553
2554 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002555 {
2556 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002557 smsg(_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002558 verbose_leave();
2559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560
2561 /* Expand wildcards, invoke the callback for each match. */
2562 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01002563 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 {
2565 for (i = 0; i < num_files; ++i)
2566 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002567 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01002569 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 break;
2571 }
2572 FreeWild(num_files, files);
2573 }
2574 }
2575 }
2576 }
2577 }
2578 vim_free(buf);
2579 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002580 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002581 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002582 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
2583
2584 if (flags & DIP_ERR)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002585 semsg(_(e_dirnotf), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002586 else if (p_verbose > 0)
2587 {
2588 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002589 smsg(_("not found in '%s': \"%s\""), basepath, name);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01002590 verbose_leave();
2591 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002592 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593
2594#ifdef AMIGA
2595 proc->pr_WindowPtr = save_winptr;
2596#endif
2597
2598 return did_one ? OK : FAIL;
2599}
2600
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002601/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002602 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002603 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002604 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
2605 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002606 * Returns OK when at least one match found, FAIL otherwise.
2607 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002608 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002609 * passed by reference in this case, setting it to NULL indicates that callback
2610 * has done its job.
2611 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002612 static int
2613do_in_path_and_pp(
2614 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002615 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002616 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002617 void (*callback)(char_u *fname, void *ck),
2618 void *cookie)
2619{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002620 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002621 char_u *s;
2622 int len;
2623 char *start_dir = "pack/*/start/*/%s";
2624 char *opt_dir = "pack/*/opt/*/%s";
2625
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002626 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002627 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002628
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002629 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002630 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002631 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002632 s = alloc(len);
2633 if (s == NULL)
2634 return FAIL;
2635 vim_snprintf((char *)s, len, start_dir, name);
2636 done = do_in_path(p_pp, s, flags, callback, cookie);
2637 vim_free(s);
2638 }
2639
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01002640 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002641 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01002642 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01002643 s = alloc(len);
2644 if (s == NULL)
2645 return FAIL;
2646 vim_snprintf((char *)s, len, opt_dir, name);
2647 done = do_in_path(p_pp, s, flags, callback, cookie);
2648 vim_free(s);
2649 }
2650
2651 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002652}
2653
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002654/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002655 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
2656 */
2657 int
2658do_in_runtimepath(
2659 char_u *name,
2660 int flags,
2661 void (*callback)(char_u *fname, void *ck),
2662 void *cookie)
2663{
2664 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
2665}
2666
2667/*
2668 * Source the file "name" from all directories in 'runtimepath'.
2669 * "name" can contain wildcards.
2670 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
2671 *
2672 * return FAIL when no file could be sourced, OK otherwise.
2673 */
2674 int
2675source_runtime(char_u *name, int flags)
2676{
2677 return source_in_path(p_rtp, name, flags);
2678}
2679
2680/*
2681 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
2682 */
2683 int
2684source_in_path(char_u *path, char_u *name, int flags)
2685{
2686 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
2687}
2688
2689
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002690#if defined(FEAT_EVAL) || defined(PROTO)
2691
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02002692/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002693 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002694 */
2695 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01002696source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002697{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002698 int num_files;
2699 char_u **files;
2700 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002701
Bram Moolenaarf3654822016-03-04 22:12:23 +01002702 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002703 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01002704 for (i = 0; i < num_files; ++i)
2705 (void)do_source(files[i], FALSE, DOSO_NONE);
2706 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002707 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01002708}
2709
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002710/*
2711 * Add the package directory to 'runtimepath'.
2712 */
2713 static int
2714add_pack_dir_to_rtp(char_u *fname)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002715{
Bram Moolenaarf3654822016-03-04 22:12:23 +01002716 char_u *p4, *p3, *p2, *p1, *p;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002717 char_u *entry;
2718 char_u *insp = NULL;
Bram Moolenaar91715872016-03-03 17:13:03 +01002719 int c;
2720 char_u *new_rtp;
2721 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002722 size_t oldlen;
2723 size_t addlen;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002724 size_t new_rtp_len;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002725 char_u *afterdir = NULL;
Bram Moolenaarb0550662016-05-31 21:37:36 +02002726 size_t afterlen = 0;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002727 char_u *after_insp = NULL;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002728 char_u *ffname = NULL;
Bram Moolenaarfef524b2016-07-02 22:07:22 +02002729 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002730 char_u *buf = NULL;
2731 char_u *rtp_ffname;
2732 int match;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002733 int retval = FAIL;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002734
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002735 p4 = p3 = p2 = p1 = get_past_head(fname);
2736 for (p = p1; *p; MB_PTR_ADV(p))
2737 if (vim_ispathsep_nocolon(*p))
2738 {
2739 p4 = p3; p3 = p2; p2 = p1; p1 = p;
2740 }
2741
2742 /* now we have:
2743 * rtp/pack/name/start/name
2744 * p4 p3 p2 p1
2745 *
2746 * find the part up to "pack" in 'runtimepath' */
2747 c = *++p4; /* append pathsep in order to expand symlink */
2748 *p4 = NUL;
2749 ffname = fix_fname(fname);
2750 *p4 = c;
Bram Moolenaar91715872016-03-03 17:13:03 +01002751 if (ffname == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002752 return FAIL;
2753
Bram Moolenaar99396d42018-09-08 18:21:16 +02002754 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
2755 // Also stop at the first "after" directory.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002756 fname_len = STRLEN(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002757 buf = alloc(MAXPATHL);
2758 if (buf == NULL)
2759 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002760 for (entry = p_rtp; *entry != NUL; )
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002761 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002762 char_u *cur_entry = entry;
2763
2764 copy_option_part(&entry, buf, MAXPATHL, ",");
2765 if (insp == NULL)
2766 {
2767 add_pathsep(buf);
2768 rtp_ffname = fix_fname(buf);
2769 if (rtp_ffname == NULL)
2770 goto theend;
2771 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
2772 vim_free(rtp_ffname);
2773 if (match)
2774 // Insert "ffname" after this entry (and comma).
2775 insp = entry;
2776 }
2777
2778 if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
2779 && p > buf
2780 && vim_ispathsep(p[-1])
2781 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
2782 {
2783 if (insp == NULL)
2784 // Did not find "ffname" before the first "after" directory,
2785 // insert it before this entry.
2786 insp = cur_entry;
2787 after_insp = cur_entry;
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002788 break;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002789 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002790 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002791
Bram Moolenaar99396d42018-09-08 18:21:16 +02002792 if (insp == NULL)
2793 // Both "fname" and "after" not found, append at the end.
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002794 insp = p_rtp + STRLEN(p_rtp);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002795
Bram Moolenaar99396d42018-09-08 18:21:16 +02002796 // check if rtp/pack/name/start/name/after exists
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002797 afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
2798 if (afterdir != NULL && mch_isdir(afterdir))
Bram Moolenaar99396d42018-09-08 18:21:16 +02002799 afterlen = STRLEN(afterdir) + 1; // add one for comma
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002800
2801 oldlen = STRLEN(p_rtp);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002802 addlen = STRLEN(fname) + 1; // add one for comma
2803 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); // add one for NUL
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002804 if (new_rtp == NULL)
2805 goto theend;
Bram Moolenaar99396d42018-09-08 18:21:16 +02002806
2807 // We now have 'rtp' parts: {keep}{keep_after}{rest}.
2808 // Create new_rtp, first: {keep},{fname}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002809 keep = (int)(insp - p_rtp);
2810 mch_memmove(new_rtp, p_rtp, keep);
Bram Moolenaar99396d42018-09-08 18:21:16 +02002811 new_rtp_len = keep;
2812 if (*insp == NUL)
2813 new_rtp[new_rtp_len++] = ','; // add comma before
2814 mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
2815 new_rtp_len += addlen - 1;
2816 if (*insp != NUL)
2817 new_rtp[new_rtp_len++] = ','; // add comma after
2818
2819 if (afterlen > 0 && after_insp != NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01002820 {
Bram Moolenaar99396d42018-09-08 18:21:16 +02002821 int keep_after = (int)(after_insp - p_rtp);
2822
2823 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
2824 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
2825 keep_after - keep);
2826 new_rtp_len += keep_after - keep;
2827 mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
2828 new_rtp_len += afterlen - 1;
2829 new_rtp[new_rtp_len++] = ',';
2830 keep = keep_after;
2831 }
2832
2833 if (p_rtp[keep] != NUL)
2834 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
2835 mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
2836 else
2837 new_rtp[new_rtp_len] = NUL;
2838
2839 if (afterlen > 0 && after_insp == NULL)
2840 {
2841 // Append afterdir when "after" was not found:
2842 // {keep},{fname}{rest},{afterdir}
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002843 STRCAT(new_rtp, ",");
2844 STRCAT(new_rtp, afterdir);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002845 }
Bram Moolenaar99396d42018-09-08 18:21:16 +02002846
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002847 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
2848 vim_free(new_rtp);
2849 retval = OK;
Bram Moolenaarf3654822016-03-04 22:12:23 +01002850
2851theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01002852 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01002853 vim_free(ffname);
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002854 vim_free(afterdir);
2855 return retval;
2856}
2857
2858/*
2859 * Load scripts in "plugin" and "ftdetect" directories of the package.
2860 */
2861 static int
2862load_pack_plugin(char_u *fname)
2863{
2864 static char *plugpat = "%s/plugin/**/*.vim";
2865 static char *ftpat = "%s/ftdetect/*.vim";
2866 int len;
2867 char_u *ffname = fix_fname(fname);
2868 char_u *pat = NULL;
2869 int retval = FAIL;
2870
2871 if (ffname == NULL)
2872 return FAIL;
2873 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
2874 pat = alloc(len);
2875 if (pat == NULL)
2876 goto theend;
2877 vim_snprintf((char *)pat, len, plugpat, ffname);
2878 source_all_matches(pat);
2879
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002880 {
2881 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
2882
2883 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
2884 * found when it loads. */
2885 if (cmd != NULL && eval_to_number(cmd) > 0)
2886 {
2887 do_cmdline_cmd((char_u *)"augroup filetypedetect");
2888 vim_snprintf((char *)pat, len, ftpat, ffname);
2889 source_all_matches(pat);
2890 do_cmdline_cmd((char_u *)"augroup END");
2891 }
2892 vim_free(cmd);
2893 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002894 vim_free(pat);
2895 retval = OK;
2896
2897theend:
2898 vim_free(ffname);
2899 return retval;
2900}
2901
2902/* used for "cookie" of add_pack_plugin() */
2903static int APP_ADD_DIR;
2904static int APP_LOAD;
2905static int APP_BOTH;
2906
2907 static void
2908add_pack_plugin(char_u *fname, void *cookie)
2909{
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002910 if (cookie != &APP_LOAD)
2911 {
2912 char_u *buf = alloc(MAXPATHL);
2913 char_u *p;
2914 int found = FALSE;
2915
2916 if (buf == NULL)
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002917 return;
Bram Moolenaarf98a39c2018-04-18 22:18:23 +02002918 p = p_rtp;
2919 while (*p != NUL)
2920 {
2921 copy_option_part(&p, buf, MAXPATHL, ",");
2922 if (pathcmp((char *)buf, (char *)fname, -1) == 0)
2923 {
2924 found = TRUE;
2925 break;
2926 }
2927 }
2928 vim_free(buf);
2929 if (!found)
2930 /* directory is not yet in 'runtimepath', add it */
2931 if (add_pack_dir_to_rtp(fname) == FAIL)
2932 return;
2933 }
Bram Moolenaar2374faa2018-02-04 17:47:42 +01002934
2935 if (cookie != &APP_ADD_DIR)
2936 load_pack_plugin(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002937}
2938
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002939/*
2940 * Add all packages in the "start" directory to 'runtimepath'.
2941 */
2942 void
2943add_pack_start_dirs(void)
2944{
2945 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2946 add_pack_plugin, &APP_ADD_DIR);
2947}
2948
2949/*
2950 * Load plugins from all packages in the "start" directory.
2951 */
2952 void
2953load_start_packages(void)
2954{
2955 did_source_packages = TRUE;
2956 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
2957 add_pack_plugin, &APP_LOAD);
2958}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002959
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002960/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002961 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01002962 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002963 */
2964 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002965ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002966{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002967 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002968 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02002969 /* First do a round to add all directories to 'runtimepath', then load
2970 * the plugins. This allows for plugins to use an autoload directory
2971 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02002972 add_pack_start_dirs();
2973 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01002974 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002975}
2976
2977/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01002978 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01002979 */
2980 void
2981ex_packadd(exarg_T *eap)
2982{
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002983 static char *plugpat = "pack/*/%s/%s";
Bram Moolenaar91715872016-03-03 17:13:03 +01002984 int len;
2985 char *pat;
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002986 int round;
2987 int res = OK;
Bram Moolenaar91715872016-03-03 17:13:03 +01002988
Bram Moolenaar9e1d3992017-12-17 14:26:46 +01002989 /* Round 1: use "start", round 2: use "opt". */
2990 for (round = 1; round <= 2; ++round)
2991 {
2992 /* Only look under "start" when loading packages wasn't done yet. */
2993 if (round == 1 && did_source_packages)
2994 continue;
2995
2996 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
2997 pat = (char *)alloc(len);
2998 if (pat == NULL)
2999 return;
3000 vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
3001 /* The first round don't give a "not found" error, in the second round
3002 * only when nothing was found in the first round. */
3003 res = do_in_path(p_pp, (char_u *)pat,
3004 DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
3005 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
3006 vim_free(pat);
3007 }
Bram Moolenaar91715872016-03-03 17:13:03 +01003008}
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003009#endif
Bram Moolenaar91715872016-03-03 17:13:03 +01003010
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003011#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012/*
3013 * ":options"
3014 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003016ex_options(
3017 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018{
Bram Moolenaare0b59492019-05-21 20:54:45 +02003019 vim_setenv((char_u *)"OPTWIN_CMD",
3020 (char_u *)(cmdmod.tab ? "tab"
3021 : (cmdmod.split & WSP_VERT) ? "vert" : ""));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3023}
3024#endif
3025
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003026#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3027
3028# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3029/*
3030 * Detect Python 3 or 2, and initialize 'pyxversion'.
3031 */
3032 void
3033init_pyxversion(void)
3034{
3035 if (p_pyx == 0)
3036 {
3037 if (python3_enabled(FALSE))
3038 p_pyx = 3;
3039 else if (python_enabled(FALSE))
3040 p_pyx = 2;
3041 }
3042}
3043# endif
3044
3045/*
3046 * Does a file contain one of the following strings at the beginning of any
3047 * line?
3048 * "#!(any string)python2" => returns 2
3049 * "#!(any string)python3" => returns 3
3050 * "# requires python 2.x" => returns 2
3051 * "# requires python 3.x" => returns 3
3052 * otherwise return 0.
3053 */
3054 static int
3055requires_py_version(char_u *filename)
3056{
3057 FILE *file;
3058 int requires_py_version = 0;
3059 int i, lines;
3060
3061 lines = (int)p_mls;
3062 if (lines < 0)
3063 lines = 5;
3064
3065 file = mch_fopen((char *)filename, "r");
3066 if (file != NULL)
3067 {
3068 for (i = 0; i < lines; i++)
3069 {
3070 if (vim_fgets(IObuff, IOSIZE, file))
3071 break;
3072 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3073 {
3074 /* Check shebang. */
3075 if (strstr((char *)IObuff + 2, "python2") != NULL)
3076 {
3077 requires_py_version = 2;
3078 break;
3079 }
3080 if (strstr((char *)IObuff + 2, "python3") != NULL)
3081 {
3082 requires_py_version = 3;
3083 break;
3084 }
3085 }
3086 IObuff[21] = '\0';
3087 if (STRCMP("# requires python 2.x", IObuff) == 0)
3088 {
3089 requires_py_version = 2;
3090 break;
3091 }
3092 if (STRCMP("# requires python 3.x", IObuff) == 0)
3093 {
3094 requires_py_version = 3;
3095 break;
3096 }
3097 }
3098 fclose(file);
3099 }
3100 return requires_py_version;
3101}
3102
3103
3104/*
3105 * Source a python file using the requested python version.
3106 */
3107 static void
3108source_pyx_file(exarg_T *eap, char_u *fname)
3109{
3110 exarg_T ex;
3111 int v = requires_py_version(fname);
3112
3113# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3114 init_pyxversion();
3115# endif
3116 if (v == 0)
3117 {
3118# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3119 /* user didn't choose a preference, 'pyx' is used */
3120 v = p_pyx;
3121# elif defined(FEAT_PYTHON)
3122 v = 2;
3123# elif defined(FEAT_PYTHON3)
3124 v = 3;
3125# endif
3126 }
3127
3128 /*
3129 * now source, if required python version is not supported show
3130 * unobtrusive message.
3131 */
3132 if (eap == NULL)
3133 vim_memset(&ex, 0, sizeof(ex));
3134 else
3135 ex = *eap;
3136 ex.arg = fname;
3137 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3138
3139 if (v == 2)
3140 {
3141# ifdef FEAT_PYTHON
3142 ex_pyfile(&ex);
3143# else
3144 vim_snprintf((char *)IObuff, IOSIZE,
3145 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3146 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003147 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003148# endif
3149 return;
3150 }
3151 else
3152 {
3153# ifdef FEAT_PYTHON3
3154 ex_py3file(&ex);
3155# else
3156 vim_snprintf((char *)IObuff, IOSIZE,
3157 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3158 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003159 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003160# endif
3161 return;
3162 }
3163}
3164
3165/*
3166 * ":pyxfile {fname}"
3167 */
3168 void
3169ex_pyxfile(exarg_T *eap)
3170{
3171 source_pyx_file(eap, eap->arg);
3172}
3173
3174/*
3175 * ":pyx"
3176 */
3177 void
3178ex_pyx(exarg_T *eap)
3179{
3180# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3181 init_pyxversion();
3182 if (p_pyx == 2)
3183 ex_python(eap);
3184 else
3185 ex_py3(eap);
3186# elif defined(FEAT_PYTHON)
3187 ex_python(eap);
3188# elif defined(FEAT_PYTHON3)
3189 ex_py3(eap);
3190# endif
3191}
3192
3193/*
3194 * ":pyxdo"
3195 */
3196 void
3197ex_pyxdo(exarg_T *eap)
3198{
3199# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3200 init_pyxversion();
3201 if (p_pyx == 2)
3202 ex_pydo(eap);
3203 else
3204 ex_py3do(eap);
3205# elif defined(FEAT_PYTHON)
3206 ex_pydo(eap);
3207# elif defined(FEAT_PYTHON3)
3208 ex_py3do(eap);
3209# endif
3210}
3211
3212#endif
3213
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214/*
3215 * ":source {fname}"
3216 */
3217 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003218ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219{
3220#ifdef FEAT_BROWSE
3221 if (cmdmod.browse)
3222 {
3223 char_u *fname = NULL;
3224
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003225 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaarc36651b2018-04-29 12:22:56 +02003226 NULL, NULL,
3227 (char_u *)_(BROWSE_FILTER_MACROS), NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 if (fname != NULL)
3229 {
3230 cmd_source(fname, eap);
3231 vim_free(fname);
3232 }
3233 }
3234 else
3235#endif
3236 cmd_source(eap->arg, eap);
3237}
3238
3239 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003240cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241{
3242 if (*fname == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003243 emsg(_(e_argreq));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003246 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003247 * Need to execute the commands directly. This is required at least
3248 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249 * - ":g" command busy
3250 * - after ":argdo", ":windo" or ":bufdo"
3251 * - another command follows
3252 * - inside a loop
3253 */
3254 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3255#ifdef FEAT_EVAL
3256 || eap->cstack->cs_idx >= 0
3257#endif
3258 );
3259
3260 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003261 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003262 semsg(_(e_notopen), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263}
3264
3265/*
3266 * ":source" and associated commands.
3267 */
3268/*
3269 * Structure used to store info for each sourced file.
3270 * It is shared between do_source() and getsourceline().
3271 * This is required, because it needs to be handed to do_cmdline() and
3272 * sourcing can be done recursively.
3273 */
3274struct source_cookie
3275{
3276 FILE *fp; /* opened file for sourcing */
3277 char_u *nextline; /* if not NULL: line that was read ahead */
3278 int finished; /* ":finish" used */
Bram Moolenaar00590742019-02-15 21:06:09 +01003279#ifdef USE_CRNL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3281 int error; /* TRUE if LF found after CR-LF */
3282#endif
3283#ifdef FEAT_EVAL
3284 linenr_T breakpoint; /* next line with breakpoint or zero */
3285 char_u *fname; /* name of sourced file */
3286 int dbg_tick; /* debug_tick when breakpoint was set */
3287 int level; /* top nesting level of sourced file */
3288#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 vimconv_T conv; /* type of conversion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290};
3291
3292#ifdef FEAT_EVAL
3293/*
3294 * Return the address holding the next breakpoint line for a source cookie.
3295 */
3296 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003297source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298{
3299 return &((struct source_cookie *)cookie)->breakpoint;
3300}
3301
3302/*
3303 * Return the address holding the debug tick for a source cookie.
3304 */
3305 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003306source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307{
3308 return &((struct source_cookie *)cookie)->dbg_tick;
3309}
3310
3311/*
3312 * Return the nesting level for a source cookie.
3313 */
3314 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003315source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316{
3317 return ((struct source_cookie *)cookie)->level;
3318}
3319#endif
3320
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003321static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322
Bram Moolenaar4f974752019-02-17 17:44:42 +01003323#if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003324# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325/*
3326 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003327 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 */
3329 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003330fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331{
Bram Moolenaar4f974752019-02-17 17:44:42 +01003332# ifdef MSWIN
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003333 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3334# else
3335 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003336# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337
3338 if (fd_tmp == -1)
3339 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003340
3341# ifdef HAVE_FD_CLOEXEC
3342 {
3343 int fdflags = fcntl(fd_tmp, F_GETFD);
3344 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003345 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003346 }
3347# endif
3348
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 return fdopen(fd_tmp, READBIN);
3350}
3351#endif
3352
3353
3354/*
3355 * do_source: Read the file "fname" and execute its lines as EX commands.
3356 *
3357 * This function may be called recursively!
3358 *
3359 * return FAIL if file could not be opened, OK otherwise
3360 */
3361 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003362do_source(
3363 char_u *fname,
3364 int check_other, /* check for .vimrc and _vimrc */
3365 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366{
3367 struct source_cookie cookie;
3368 char_u *save_sourcing_name;
3369 linenr_T save_sourcing_lnum;
3370 char_u *p;
3371 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003372 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 int retval = FAIL;
3374#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003375 sctx_T save_current_sctx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 static scid_T last_current_SID = 0;
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003377 static int last_current_SID_seq = 0;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003378 funccal_entry_T funccalp_entry;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003380 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003382 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383 int stat_ok;
3384# endif
3385#endif
3386#ifdef STARTUPTIME
3387 struct timeval tv_rel;
3388 struct timeval tv_start;
3389#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003390#ifdef FEAT_PROFILE
3391 proftime_T wait_start;
3392#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003393 int trigger_source_post = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 if (p == NULL)
3397 return retval;
3398 fname_exp = fix_fname(p);
3399 vim_free(p);
3400 if (fname_exp == NULL)
3401 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 if (mch_isdir(fname_exp))
3403 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003404 smsg(_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405 goto theend;
3406 }
3407
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003408 /* Apply SourceCmd autocommands, they should get the file and source it. */
3409 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3410 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3411 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003412 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003413#ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003414 retval = aborting() ? FAIL : OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003415#else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003416 retval = OK;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003417#endif
Bram Moolenaar2b618522019-01-12 13:26:03 +01003418 if (retval == OK)
3419 // Apply SourcePost autocommands.
3420 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
3421 FALSE, curbuf);
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003422 goto theend;
3423 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003424
3425 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003426 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003427
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003428#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3430#else
3431 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3432#endif
3433 if (cookie.fp == NULL && check_other)
3434 {
3435 /*
3436 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3437 * and ".exrc" by "_exrc" or vice versa.
3438 */
3439 p = gettail(fname_exp);
3440 if ((*p == '.' || *p == '_')
3441 && (STRICMP(p + 1, "vimrc") == 0
3442 || STRICMP(p + 1, "gvimrc") == 0
3443 || STRICMP(p + 1, "exrc") == 0))
3444 {
3445 if (*p == '_')
3446 *p = '.';
3447 else
3448 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003449#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003450 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3451#else
3452 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3453#endif
3454 }
3455 }
3456
3457 if (cookie.fp == NULL)
3458 {
3459 if (p_verbose > 0)
3460 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003461 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003462 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003463 smsg(_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003465 smsg(_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003466 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003467 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 }
3469 goto theend;
3470 }
3471
3472 /*
3473 * The file exists.
3474 * - In verbose mode, give a message.
3475 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3476 */
3477 if (p_verbose > 1)
3478 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003479 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480 if (sourcing_name == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003481 smsg(_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003483 smsg(_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003484 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003485 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003487 if (is_vimrc == DOSO_VIMRC)
3488 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3489 else if (is_vimrc == DOSO_GVIMRC)
3490 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491
3492#ifdef USE_CRNL
3493 /* If no automatic file format: Set default to CR-NL. */
3494 if (*p_ffs == NUL)
3495 cookie.fileformat = EOL_DOS;
3496 else
3497 cookie.fileformat = EOL_UNKNOWN;
3498 cookie.error = FALSE;
3499#endif
3500
Bram Moolenaar071d4272004-06-13 20:20:40 +00003501 cookie.nextline = NULL;
3502 cookie.finished = FALSE;
3503
3504#ifdef FEAT_EVAL
3505 /*
3506 * Check if this script has a breakpoint.
3507 */
3508 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3509 cookie.fname = fname_exp;
3510 cookie.dbg_tick = debug_tick;
3511
3512 cookie.level = ex_nesting_level;
3513#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514
3515 /*
3516 * Keep the sourcing name/lnum, for recursive calls.
3517 */
3518 save_sourcing_name = sourcing_name;
3519 sourcing_name = fname_exp;
3520 save_sourcing_lnum = sourcing_lnum;
3521 sourcing_lnum = 0;
3522
3523#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003524 if (time_fd != NULL)
3525 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526#endif
3527
3528#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003529# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003530 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003531 prof_child_enter(&wait_start); /* entering a child now */
3532# endif
3533
3534 /* Don't use local function variables, if called from a function.
3535 * Also starts profiling timer for nested script. */
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003536 save_funccal(&funccalp_entry);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003537
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003538 save_current_sctx = current_sctx;
3539 current_sctx.sc_lnum = 0;
3540 current_sctx.sc_version = 1;
3541
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003542 // Check if this script was sourced before to finds its SID.
3543 // If it's new, generate a new SID.
3544 // Always use a new sequence number.
Bram Moolenaarded5f1b2018-11-10 17:33:29 +01003545 current_sctx.sc_seq = ++last_current_SID_seq;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546# ifdef UNIX
3547 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3548# endif
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003549 for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
3550 --current_sctx.sc_sid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003551 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003552 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003553 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 && (
3555# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003556 /* Compare dev/ino when possible, it catches symbolic
3557 * links. Also compare file names, the inode may change
3558 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003559 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003560 && (si->sn_dev == st.st_dev
3561 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003562# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003563 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003565 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003566 if (current_sctx.sc_sid == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003568 current_sctx.sc_sid = ++last_current_SID;
3569 if (ga_grow(&script_items,
3570 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003571 goto almosttheend;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003572 while (script_items.ga_len < current_sctx.sc_sid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003574 ++script_items.ga_len;
3575 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3576# ifdef FEAT_PROFILE
3577 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003579 }
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003580 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003581 si->sn_name = fname_exp;
Bram Moolenaarea56e162019-01-12 15:15:38 +01003582 fname_exp = vim_strsave(si->sn_name); // used for autocmd
Bram Moolenaar05159a02005-02-26 23:04:13 +00003583# ifdef UNIX
3584 if (stat_ok)
3585 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003586 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003587 si->sn_dev = st.st_dev;
3588 si->sn_ino = st.st_ino;
3589 }
3590 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003591 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003592# endif
3593
Bram Moolenaar071d4272004-06-13 20:20:40 +00003594 /* Allocate the local script variables to use for this script. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003595 new_script_vars(current_sctx.sc_sid);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003596 }
3597
Bram Moolenaar05159a02005-02-26 23:04:13 +00003598# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003599 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003600 {
3601 int forceit;
3602
3603 /* Check if we do profiling for this script. */
3604 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3605 {
3606 script_do_profile(si);
3607 si->sn_pr_force = forceit;
3608 }
3609 if (si->sn_prof_on)
3610 {
3611 ++si->sn_pr_count;
3612 profile_start(&si->sn_pr_start);
3613 profile_zero(&si->sn_pr_children);
3614 }
3615 }
3616# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617#endif
3618
Bram Moolenaar67435d92017-10-19 21:04:37 +02003619 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3620
3621 /* Read the first line so we can check for a UTF-8 BOM. */
3622 firstline = getsourceline(0, (void *)&cookie, 0);
3623 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3624 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3625 {
3626 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3627 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3628 p = string_convert(&cookie.conv, firstline + 3, NULL);
3629 if (p == NULL)
3630 p = vim_strsave(firstline + 3);
3631 if (p != NULL)
3632 {
3633 vim_free(firstline);
3634 firstline = p;
3635 }
3636 }
Bram Moolenaar67435d92017-10-19 21:04:37 +02003637
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638 /*
3639 * Call do_cmdline, which will call getsourceline() to get the lines.
3640 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003641 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003644
3645#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003646 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003647 {
3648 /* Get "si" again, "script_items" may have been reallocated. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003649 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003650 if (si->sn_prof_on)
3651 {
3652 profile_end(&si->sn_pr_start);
3653 profile_sub_wait(&wait_start, &si->sn_pr_start);
3654 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003655 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3656 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003657 }
3658 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659#endif
3660
3661 if (got_int)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003662 emsg(_(e_interr));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 sourcing_name = save_sourcing_name;
3664 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 if (p_verbose > 1)
3666 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003667 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003668 smsg(_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 if (sourcing_name != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003670 smsg(_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003671 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 }
3673#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003674 if (time_fd != NULL)
3675 {
3676 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3677 time_msg((char *)IObuff, &tv_start);
3678 time_pop(&tv_rel);
3679 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680#endif
3681
Bram Moolenaar2b618522019-01-12 13:26:03 +01003682 if (!got_int)
3683 trigger_source_post = TRUE;
3684
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685#ifdef FEAT_EVAL
3686 /*
3687 * After a "finish" in debug mode, need to break at first command of next
3688 * sourced file.
3689 */
3690 if (save_debug_break_level > ex_nesting_level
3691 && debug_break_level == ex_nesting_level)
3692 ++debug_break_level;
3693#endif
3694
Bram Moolenaar05159a02005-02-26 23:04:13 +00003695#ifdef FEAT_EVAL
3696almosttheend:
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003697 current_sctx = save_current_sctx;
Bram Moolenaar27e80c82018-10-14 21:41:01 +02003698 restore_funccal();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003699# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003700 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003701 prof_child_exit(&wait_start); /* leaving a child now */
3702# endif
3703#endif
3704 fclose(cookie.fp);
3705 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003706 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003707 convert_setup(&cookie.conv, NULL, NULL);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003708
Bram Moolenaar2b618522019-01-12 13:26:03 +01003709 if (trigger_source_post)
Bram Moolenaarea56e162019-01-12 15:15:38 +01003710 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
Bram Moolenaar2b618522019-01-12 13:26:03 +01003711
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712theend:
3713 vim_free(fname_exp);
3714 return retval;
3715}
3716
3717#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003718
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719/*
3720 * ":scriptnames"
3721 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722 void
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003723ex_scriptnames(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724{
3725 int i;
3726
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003727 if (eap->addr_count > 0)
3728 {
3729 // :script {scriptId}: edit the script
3730 if (eap->line2 < 1 || eap->line2 > script_items.ga_len)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003731 emsg(_(e_invarg));
Bram Moolenaar07dc18f2018-11-30 22:48:32 +01003732 else
3733 {
3734 eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
3735 do_exedit(eap, NULL);
3736 }
3737 return;
3738 }
3739
Bram Moolenaar05159a02005-02-26 23:04:13 +00003740 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3741 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003742 {
3743 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3744 NameBuff, MAXPATHL, TRUE);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003745 smsg("%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003746 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003747}
3748
3749# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3750/*
3751 * Fix slashes in the list of script names for 'shellslash'.
3752 */
3753 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003754scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755{
3756 int i;
3757
Bram Moolenaar05159a02005-02-26 23:04:13 +00003758 for (i = 1; i <= script_items.ga_len; ++i)
3759 if (SCRIPT_ITEM(i).sn_name != NULL)
3760 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761}
3762# endif
3763
3764/*
3765 * Get a pointer to a script name. Used for ":verbose set".
3766 */
3767 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003768get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769{
3770 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003771 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003773 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003775 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003776 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003777 return (char_u *)_("environment variable");
3778 if (id == SID_ERROR)
3779 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003780 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003781}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003782
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003783# if defined(EXITFREE) || defined(PROTO)
3784 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003785free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003786{
3787 int i;
3788
3789 for (i = script_items.ga_len; i > 0; --i)
3790 vim_free(SCRIPT_ITEM(i).sn_name);
3791 ga_clear(&script_items);
3792}
3793# endif
3794
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795#endif
3796
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797/*
3798 * Get one full line from a sourced file.
3799 * Called by do_cmdline() when it's called from do_source().
3800 *
3801 * Return a pointer to the line in allocated memory.
3802 * Return NULL for end-of-file or some error.
3803 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003805getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806{
3807 struct source_cookie *sp = (struct source_cookie *)cookie;
3808 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003809 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810
3811#ifdef FEAT_EVAL
3812 /* If breakpoints have been added/deleted need to check for it. */
3813 if (sp->dbg_tick < debug_tick)
3814 {
3815 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3816 sp->dbg_tick = debug_tick;
3817 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003818# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003819 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003820 script_line_end();
3821# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822#endif
3823 /*
3824 * Get current line. If there is a read-ahead line, use it, otherwise get
3825 * one now.
3826 */
3827 if (sp->finished)
3828 line = NULL;
3829 else if (sp->nextline == NULL)
3830 line = get_one_sourceline(sp);
3831 else
3832 {
3833 line = sp->nextline;
3834 sp->nextline = NULL;
3835 ++sourcing_lnum;
3836 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003837#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003838 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003839 script_line_start();
3840#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841
3842 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3843 * contain the 'C' flag. */
3844 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3845 {
3846 /* compensate for the one line read-ahead */
3847 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003848
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003849 // Get the next line and concatenate it when it starts with a
3850 // backslash. We always need to read the next line, keep it in
3851 // sp->nextline.
3852 /* Also check for a comment in between continuation lines: "\ */
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003853 sp->nextline = get_one_sourceline(sp);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003854 if (sp->nextline != NULL
3855 && (*(p = skipwhite(sp->nextline)) == '\\'
3856 || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003857 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003858 garray_T ga;
3859
Bram Moolenaarb549a732012-02-22 18:29:33 +01003860 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003861 ga_concat(&ga, line);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003862 if (*p == '\\')
3863 ga_concat(&ga, p + 1);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003864 for (;;)
3865 {
3866 vim_free(sp->nextline);
3867 sp->nextline = get_one_sourceline(sp);
3868 if (sp->nextline == NULL)
3869 break;
3870 p = skipwhite(sp->nextline);
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003871 if (*p == '\\')
Bram Moolenaarb549a732012-02-22 18:29:33 +01003872 {
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003873 // Adjust the growsize to the current length to speed up
3874 // concatenating many lines.
3875 if (ga.ga_len > 400)
3876 {
3877 if (ga.ga_len > 8000)
3878 ga.ga_growsize = 8000;
3879 else
3880 ga.ga_growsize = ga.ga_len;
3881 }
3882 ga_concat(&ga, p + 1);
Bram Moolenaarb549a732012-02-22 18:29:33 +01003883 }
Bram Moolenaar67f8ab82018-09-11 22:37:29 +02003884 else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ')
3885 break;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003886 }
3887 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003889 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890 }
3891 }
3892
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3894 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003895 char_u *s;
3896
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897 /* Convert the encoding of the script line. */
3898 s = string_convert(&sp->conv, line, NULL);
3899 if (s != NULL)
3900 {
3901 vim_free(line);
3902 line = s;
3903 }
3904 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905
3906#ifdef FEAT_EVAL
3907 /* Did we encounter a breakpoint? */
3908 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3909 {
3910 dbg_breakpoint(sp->fname, sourcing_lnum);
3911 /* Find next breakpoint. */
3912 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3913 sp->dbg_tick = debug_tick;
3914 }
3915#endif
3916
3917 return line;
3918}
3919
3920 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003921get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003922{
3923 garray_T ga;
3924 int len;
3925 int c;
3926 char_u *buf;
3927#ifdef USE_CRNL
3928 int has_cr; /* CR-LF found */
3929#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930 int have_read = FALSE;
3931
3932 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003933 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003934
3935 /*
3936 * Loop until there is a finished line (or end-of-file).
3937 */
3938 sourcing_lnum++;
3939 for (;;)
3940 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003941 /* make room to read at least 120 (more) characters */
3942 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943 break;
3944 buf = (char_u *)ga.ga_data;
3945
Bram Moolenaar00590742019-02-15 21:06:09 +01003946 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
Bram Moolenaar86b68352004-12-27 21:59:20 +00003947 sp->fp) == NULL)
Bram Moolenaar00590742019-02-15 21:06:09 +01003948 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003949 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950#ifdef USE_CRNL
3951 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3952 * CTRL-Z by its own, or after a NL. */
3953 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3954 && sp->fileformat == EOL_DOS
3955 && buf[len - 1] == Ctrl_Z)
3956 {
3957 buf[len - 1] = NUL;
3958 break;
3959 }
3960#endif
3961
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 ga.ga_len = len;
3964
3965 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003966 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003967 continue;
3968
3969 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3970 {
3971#ifdef USE_CRNL
3972 has_cr = (len >= 2 && buf[len - 2] == '\r');
3973 if (sp->fileformat == EOL_UNKNOWN)
3974 {
3975 if (has_cr)
3976 sp->fileformat = EOL_DOS;
3977 else
3978 sp->fileformat = EOL_UNIX;
3979 }
3980
3981 if (sp->fileformat == EOL_DOS)
3982 {
3983 if (has_cr) /* replace trailing CR */
3984 {
3985 buf[len - 2] = '\n';
3986 --len;
3987 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 }
3989 else /* lines like ":map xx yy^M" will have failed */
3990 {
3991 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003992 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01003993 msg_source(HL_ATTR(HLF_W));
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003994 emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003995 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996 sp->error = TRUE;
3997 sp->fileformat = EOL_UNIX;
3998 }
3999 }
4000#endif
4001 /* The '\n' is escaped if there is an odd number of ^V's just
4002 * before it, first set "c" just before the 'V's and then check
4003 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4004 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4005 ;
4006 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4007 {
4008 sourcing_lnum++;
4009 continue;
4010 }
4011
4012 buf[len - 1] = NUL; /* remove the NL */
4013 }
4014
4015 /*
4016 * Check for ^C here now and then, so recursive :so can be broken.
4017 */
4018 line_breakcheck();
4019 break;
4020 }
4021
4022 if (have_read)
4023 return (char_u *)ga.ga_data;
4024
4025 vim_free(ga.ga_data);
4026 return NULL;
4027}
4028
Bram Moolenaar05159a02005-02-26 23:04:13 +00004029#if defined(FEAT_PROFILE) || defined(PROTO)
4030/*
4031 * Called when starting to read a script line.
4032 * "sourcing_lnum" must be correct!
4033 * When skipping lines it may not actually be executed, but we won't find out
4034 * until later and we need to store the time now.
4035 */
4036 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004037script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004038{
4039 scriptitem_T *si;
4040 sn_prl_T *pp;
4041
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004042 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004043 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004044 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004045 if (si->sn_prof_on && sourcing_lnum >= 1)
4046 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004047 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004048 * here isn't counted. */
Bram Moolenaar67435d92017-10-19 21:04:37 +02004049 (void)ga_grow(&si->sn_prl_ga,
4050 (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004051 si->sn_prl_idx = sourcing_lnum - 1;
4052 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4053 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4054 {
4055 /* Zero counters for a line that was not used before. */
4056 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4057 pp->snp_count = 0;
4058 profile_zero(&pp->sn_prl_total);
4059 profile_zero(&pp->sn_prl_self);
4060 ++si->sn_prl_ga.ga_len;
4061 }
4062 si->sn_prl_execed = FALSE;
4063 profile_start(&si->sn_prl_start);
4064 profile_zero(&si->sn_prl_children);
4065 profile_get_wait(&si->sn_prl_wait);
4066 }
4067}
4068
4069/*
4070 * Called when actually executing a function line.
4071 */
4072 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004073script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004074{
4075 scriptitem_T *si;
4076
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004077 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004078 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004079 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004080 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4081 si->sn_prl_execed = TRUE;
4082}
4083
4084/*
Bram Moolenaar67435d92017-10-19 21:04:37 +02004085 * Called when done with a script line.
Bram Moolenaar05159a02005-02-26 23:04:13 +00004086 */
4087 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004088script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004089{
4090 scriptitem_T *si;
4091 sn_prl_T *pp;
4092
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004093 if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004094 return;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004095 si = &SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004096 if (si->sn_prof_on && si->sn_prl_idx >= 0
4097 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4098 {
4099 if (si->sn_prl_execed)
4100 {
4101 pp = &PRL_ITEM(si, si->sn_prl_idx);
4102 ++pp->snp_count;
4103 profile_end(&si->sn_prl_start);
4104 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004105 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004106 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4107 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004108 }
4109 si->sn_prl_idx = -1;
4110 }
4111}
4112#endif
4113
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114/*
4115 * ":scriptencoding": Set encoding conversion for a sourced script.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117 void
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004118ex_scriptencoding(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120 struct source_cookie *sp;
4121 char_u *name;
4122
4123 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4124 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004125 emsg(_("E167: :scriptencoding used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126 return;
4127 }
4128
4129 if (*eap->arg != NUL)
4130 {
4131 name = enc_canonize(eap->arg);
4132 if (name == NULL) /* out of memory */
4133 return;
4134 }
4135 else
4136 name = eap->arg;
4137
4138 /* Setup for conversion from the specified encoding to 'encoding'. */
4139 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4140 convert_setup(&sp->conv, name, p_enc);
4141
4142 if (name != eap->arg)
4143 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144}
4145
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004146/*
4147 * ":scriptversion": Set Vim script version for a sourced script.
4148 */
4149 void
4150ex_scriptversion(exarg_T *eap UNUSED)
4151{
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004152#ifdef FEAT_EVAL
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004153 int nr;
4154
4155 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4156 {
4157 emsg(_("E984: :scriptversion used outside of a sourced file"));
4158 return;
4159 }
4160
4161 nr = getdigits(&eap->arg);
4162 if (nr == 0 || *eap->arg != NUL)
4163 emsg(_(e_invarg));
Bram Moolenaard2e716e2019-04-20 14:39:52 +02004164 else if (nr > 3)
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004165 semsg(_("E999: scriptversion not supported: %d"), nr);
4166 else
4167 current_sctx.sc_version = nr;
Bram Moolenaar1cd4dc42019-04-04 19:06:14 +02004168#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004169}
4170
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171#if defined(FEAT_EVAL) || defined(PROTO)
4172/*
4173 * ":finish": Mark a sourced file as finished.
4174 */
4175 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004176ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177{
4178 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4179 do_finish(eap, FALSE);
4180 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004181 emsg(_("E168: :finish used outside of a sourced file"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182}
4183
4184/*
4185 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4186 * Also called for a pending finish at the ":endtry" or after returning from
4187 * an extra do_cmdline(). "reanimate" is used in the latter case.
4188 */
4189 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004190do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191{
4192 int idx;
4193
4194 if (reanimate)
4195 ((struct source_cookie *)getline_cookie(eap->getline,
4196 eap->cookie))->finished = FALSE;
4197
4198 /*
4199 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4200 * not in its finally clause (which then is to be executed next) is found.
4201 * In this case, make the ":finish" pending for execution at the ":endtry".
4202 * Otherwise, finish normally.
4203 */
4204 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4205 if (idx >= 0)
4206 {
4207 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4208 report_make_pending(CSTP_FINISH, NULL);
4209 }
4210 else
4211 ((struct source_cookie *)getline_cookie(eap->getline,
4212 eap->cookie))->finished = TRUE;
4213}
4214
4215
4216/*
4217 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4218 * message for missing ":endif".
4219 * Return FALSE when not sourcing a file.
4220 */
4221 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004222source_finished(
4223 char_u *(*fgetline)(int, void *, int),
4224 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004226 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004228 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229}
4230#endif
4231
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232/*
4233 * ":checktime [buffer]"
4234 */
4235 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004236ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237{
4238 buf_T *buf;
4239 int save_no_check_timestamps = no_check_timestamps;
4240
4241 no_check_timestamps = 0;
4242 if (eap->addr_count == 0) /* default is all buffers */
4243 check_timestamps(FALSE);
4244 else
4245 {
4246 buf = buflist_findnr((int)eap->line2);
4247 if (buf != NULL) /* cannot happen? */
4248 (void)buf_check_timestamp(buf, FALSE);
4249 }
4250 no_check_timestamps = save_no_check_timestamps;
4251}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4254 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004255# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004256 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004257get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004258{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004259 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004261 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004262 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263
Bram Moolenaar4f974752019-02-17 17:44:42 +01004264# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265 if (loc != NULL)
4266 {
4267 char_u *p;
4268
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004269 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4270 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 p = vim_strchr(loc, '=');
4272 if (p != NULL)
4273 {
4274 loc = ++p;
4275 while (*p != NUL) /* remove trailing newline */
4276 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004277 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 {
4279 *p = NUL;
4280 break;
4281 }
4282 ++p;
4283 }
4284 }
4285 }
4286# endif
4287
4288 return loc;
4289}
4290#endif
4291
4292
Bram Moolenaar4f974752019-02-17 17:44:42 +01004293#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294/*
4295 * On MS-Windows locale names are strings like "German_Germany.1252", but
4296 * gettext expects "de". Try to translate one into another here for a few
4297 * supported languages.
4298 */
4299 static char_u *
4300gettext_lang(char_u *name)
4301{
4302 int i;
4303 static char *(mtable[]) = {
4304 "afrikaans", "af",
4305 "czech", "cs",
4306 "dutch", "nl",
4307 "german", "de",
4308 "english_united kingdom", "en_GB",
4309 "spanish", "es",
4310 "french", "fr",
4311 "italian", "it",
4312 "japanese", "ja",
4313 "korean", "ko",
4314 "norwegian", "no",
4315 "polish", "pl",
4316 "russian", "ru",
4317 "slovak", "sk",
4318 "swedish", "sv",
4319 "ukrainian", "uk",
4320 "chinese_china", "zh_CN",
4321 "chinese_taiwan", "zh_TW",
4322 NULL};
4323
4324 for (i = 0; mtable[i] != NULL; i += 2)
4325 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004326 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327 return name;
4328}
4329#endif
4330
4331#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4332/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01004333 * Return TRUE when "lang" starts with a valid language name.
4334 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
4335 */
4336 static int
4337is_valid_mess_lang(char_u *lang)
4338{
4339 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
4340}
4341
4342/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343 * Obtain the current messages language. Used to set the default for
4344 * 'helplang'. May return NULL or an empty string.
4345 */
4346 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004347get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348{
4349 char_u *p;
4350
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004351# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004353 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354# else
4355 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004356 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4357 * and LC_MONETARY may be set differently for a Japanese working in the
4358 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004359 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360# endif
4361# else
4362 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004363 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364 {
4365 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01004366 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 p = mch_getenv((char_u *)"LANG");
4368 }
4369# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004370# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004371 p = gettext_lang(p);
4372# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01004373 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374}
4375#endif
4376
Bram Moolenaardef9e822004-12-31 20:58:58 +00004377/* Complicated #if; matches with where get_mess_env() is used below. */
4378#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4379 && defined(LC_MESSAGES))) \
4380 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00004381 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382/*
4383 * Get the language used for messages from the environment.
4384 */
4385 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004386get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387{
4388 char_u *p;
4389
4390 p = mch_getenv((char_u *)"LC_ALL");
4391 if (p == NULL || *p == NUL)
4392 {
4393 p = mch_getenv((char_u *)"LC_MESSAGES");
4394 if (p == NULL || *p == NUL)
4395 {
4396 p = mch_getenv((char_u *)"LANG");
4397 if (p != NULL && VIM_ISDIGIT(*p))
4398 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004399# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004401 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402# endif
4403 }
4404 }
4405 return p;
4406}
4407#endif
4408
4409#if defined(FEAT_EVAL) || defined(PROTO)
4410
4411/*
4412 * Set the "v:lang" variable according to the current locale setting.
4413 * Also do "v:lc_time"and "v:ctype".
4414 */
4415 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004416set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417{
4418 char_u *loc;
4419
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004420# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004421 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422# else
4423 /* setlocale() not supported: use the default value */
4424 loc = (char_u *)"C";
4425# endif
4426 set_vim_var_string(VV_CTYPE, loc, -1);
4427
4428 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4429 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004430# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004431 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432# else
4433 loc = get_mess_env();
4434# endif
4435 set_vim_var_string(VV_LANG, loc, -1);
4436
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004437# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004438 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004439# endif
4440 set_vim_var_string(VV_LC_TIME, loc, -1);
4441}
4442#endif
4443
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01004444#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445/*
4446 * ":language": Set the language (locale).
4447 */
4448 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004449ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004450{
4451 char *loc;
4452 char_u *p;
4453 char_u *name;
4454 int what = LC_ALL;
4455 char *whatstr = "";
4456#ifdef LC_MESSAGES
4457# define VIM_LC_MESSAGES LC_MESSAGES
4458#else
4459# define VIM_LC_MESSAGES 6789
4460#endif
4461
4462 name = eap->arg;
4463
4464 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4465 * Allow abbreviation, but require at least 3 characters to avoid
4466 * confusion with a two letter language name "me" or "ct". */
4467 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004468 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004469 {
4470 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4471 {
4472 what = VIM_LC_MESSAGES;
4473 name = skipwhite(p);
4474 whatstr = "messages ";
4475 }
4476 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4477 {
4478 what = LC_CTYPE;
4479 name = skipwhite(p);
4480 whatstr = "ctype ";
4481 }
4482 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4483 {
4484 what = LC_TIME;
4485 name = skipwhite(p);
4486 whatstr = "time ";
4487 }
4488 }
4489
4490 if (*name == NUL)
4491 {
4492#ifndef LC_MESSAGES
4493 if (what == VIM_LC_MESSAGES)
4494 p = get_mess_env();
4495 else
4496#endif
4497 p = (char_u *)setlocale(what, NULL);
4498 if (p == NULL || *p == NUL)
4499 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004500 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501 }
4502 else
4503 {
4504#ifndef LC_MESSAGES
4505 if (what == VIM_LC_MESSAGES)
4506 loc = "";
4507 else
4508#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004509 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004511#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4512 /* Make sure strtod() uses a decimal point, not a comma. */
4513 setlocale(LC_NUMERIC, "C");
4514#endif
4515 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004517 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 else
4519 {
4520#ifdef HAVE_NL_MSG_CAT_CNTR
4521 /* Need to do this for GNU gettext, otherwise cached translations
4522 * will be used again. */
4523 extern int _nl_msg_cat_cntr;
4524
4525 ++_nl_msg_cat_cntr;
4526#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004527 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4529
4530 if (what != LC_TIME)
4531 {
4532 /* Tell gettext() what to translate to. It apparently doesn't
4533 * use the currently effective locale. Also do this when
4534 * FEAT_GETTEXT isn't defined, so that shell commands use this
4535 * value. */
4536 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004537 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004539
4540 /* Clear $LANGUAGE because GNU gettext uses it. */
4541 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01004542# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004543 /* Apparently MS-Windows printf() may cause a crash when
4544 * we give it 8-bit text while it's expecting text in the
4545 * current locale. This call avoids that. */
4546 setlocale(LC_CTYPE, "C");
4547# endif
4548 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 if (what != LC_CTYPE)
4550 {
4551 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01004552#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004553 mname = gettext_lang(name);
4554#else
4555 mname = name;
4556#endif
4557 vim_setenv((char_u *)"LC_MESSAGES", mname);
4558#ifdef FEAT_MULTI_LANG
4559 set_helplang_default(mname);
4560#endif
4561 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562 }
4563
4564# ifdef FEAT_EVAL
4565 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4566 set_lang_var();
4567# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004568# ifdef FEAT_TITLE
4569 maketitle();
4570# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571 }
4572 }
4573}
4574
4575# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004576
4577static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004578
Bram Moolenaar4f974752019-02-17 17:44:42 +01004579# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004580static int did_init_locales = FALSE;
4581
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004582/* Return an array of strings for all available locales + NULL for the
4583 * last element. Return NULL in case of error. */
4584 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004585find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004586{
4587 garray_T locales_ga;
4588 char_u *loc;
4589
4590 /* Find all available locales by running command "locale -a". If this
4591 * doesn't work we won't have completion. */
4592 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004593 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004594 if (locale_a == NULL)
4595 return NULL;
4596 ga_init2(&locales_ga, sizeof(char_u *), 20);
4597
4598 /* Transform locale_a string where each locale is separated by "\n"
4599 * into an array of locale strings. */
4600 loc = (char_u *)strtok((char *)locale_a, "\n");
4601
4602 while (loc != NULL)
4603 {
4604 if (ga_grow(&locales_ga, 1) == FAIL)
4605 break;
4606 loc = vim_strsave(loc);
4607 if (loc == NULL)
4608 break;
4609
4610 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4611 loc = (char_u *)strtok(NULL, "\n");
4612 }
4613 vim_free(locale_a);
4614 if (ga_grow(&locales_ga, 1) == FAIL)
4615 {
4616 ga_clear(&locales_ga);
4617 return NULL;
4618 }
4619 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4620 return (char_u **)locales_ga.ga_data;
4621}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004622# endif
4623
4624/*
4625 * Lazy initialization of all available locales.
4626 */
4627 static void
4628init_locales(void)
4629{
Bram Moolenaar4f974752019-02-17 17:44:42 +01004630# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01004631 if (!did_init_locales)
4632 {
4633 did_init_locales = TRUE;
4634 locales = find_locales();
4635 }
4636# endif
4637}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004638
4639# if defined(EXITFREE) || defined(PROTO)
4640 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004641free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004642{
4643 int i;
4644 if (locales != NULL)
4645 {
4646 for (i = 0; locales[i] != NULL; i++)
4647 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004648 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004649 }
4650}
4651# endif
4652
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653/*
4654 * Function given to ExpandGeneric() to obtain the possible arguments of the
4655 * ":language" command.
4656 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004658get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659{
4660 if (idx == 0)
4661 return (char_u *)"messages";
4662 if (idx == 1)
4663 return (char_u *)"ctype";
4664 if (idx == 2)
4665 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004666
4667 init_locales();
4668 if (locales == NULL)
4669 return NULL;
4670 return locales[idx - 3];
4671}
4672
4673/*
4674 * Function given to ExpandGeneric() to obtain the available locales.
4675 */
4676 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004677get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004678{
4679 init_locales();
4680 if (locales == NULL)
4681 return NULL;
4682 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683}
4684# endif
4685
4686#endif