1307c5a5bSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2307c5a5bSBram Moolenaar *
3307c5a5bSBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4307c5a5bSBram Moolenaar *
5307c5a5bSBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6307c5a5bSBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7307c5a5bSBram Moolenaar * See README.txt for an overview of the Vim source code.
8307c5a5bSBram Moolenaar */
9307c5a5bSBram Moolenaar
10307c5a5bSBram Moolenaar /*
11307c5a5bSBram Moolenaar * scriptfile.c: functions for dealing with the runtime directories/files
12307c5a5bSBram Moolenaar */
13307c5a5bSBram Moolenaar
14307c5a5bSBram Moolenaar #include "vim.h"
15307c5a5bSBram Moolenaar
16da6c0334SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
17da6c0334SBram Moolenaar // The names of packages that once were loaded are remembered.
18da6c0334SBram Moolenaar static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
19da6c0334SBram Moolenaar #endif
20da6c0334SBram Moolenaar
21307c5a5bSBram Moolenaar /*
221a47ae32SBram Moolenaar * Initialize the execution stack.
231a47ae32SBram Moolenaar */
241a47ae32SBram Moolenaar void
estack_init(void)251a47ae32SBram Moolenaar estack_init(void)
261a47ae32SBram Moolenaar {
271a47ae32SBram Moolenaar estack_T *entry;
281a47ae32SBram Moolenaar
291a47ae32SBram Moolenaar if (ga_grow(&exestack, 10) == FAIL)
301a47ae32SBram Moolenaar mch_exit(0);
311a47ae32SBram Moolenaar entry = ((estack_T *)exestack.ga_data) + exestack.ga_len;
321a47ae32SBram Moolenaar entry->es_type = ETYPE_TOP;
331a47ae32SBram Moolenaar entry->es_name = NULL;
341a47ae32SBram Moolenaar entry->es_lnum = 0;
3509d4640fSBram Moolenaar #ifdef FEAT_EVAL
361a47ae32SBram Moolenaar entry->es_info.ufunc = NULL;
3709d4640fSBram Moolenaar #endif
381a47ae32SBram Moolenaar ++exestack.ga_len;
391a47ae32SBram Moolenaar }
401a47ae32SBram Moolenaar
411a47ae32SBram Moolenaar /*
421a47ae32SBram Moolenaar * Add an item to the execution stack.
431a47ae32SBram Moolenaar * Returns the new entry or NULL when out of memory.
441a47ae32SBram Moolenaar */
451a47ae32SBram Moolenaar estack_T *
estack_push(etype_T type,char_u * name,long lnum)461a47ae32SBram Moolenaar estack_push(etype_T type, char_u *name, long lnum)
471a47ae32SBram Moolenaar {
481a47ae32SBram Moolenaar estack_T *entry;
491a47ae32SBram Moolenaar
501a47ae32SBram Moolenaar // If memory allocation fails then we'll pop more than we push, eventually
511a47ae32SBram Moolenaar // at the top level it will be OK again.
521a47ae32SBram Moolenaar if (ga_grow(&exestack, 1) == OK)
531a47ae32SBram Moolenaar {
541a47ae32SBram Moolenaar entry = ((estack_T *)exestack.ga_data) + exestack.ga_len;
551a47ae32SBram Moolenaar entry->es_type = type;
561a47ae32SBram Moolenaar entry->es_name = name;
571a47ae32SBram Moolenaar entry->es_lnum = lnum;
5809d4640fSBram Moolenaar #ifdef FEAT_EVAL
591a47ae32SBram Moolenaar entry->es_info.ufunc = NULL;
6009d4640fSBram Moolenaar #endif
611a47ae32SBram Moolenaar ++exestack.ga_len;
621a47ae32SBram Moolenaar return entry;
631a47ae32SBram Moolenaar }
641a47ae32SBram Moolenaar return NULL;
651a47ae32SBram Moolenaar }
661a47ae32SBram Moolenaar
6709d4640fSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
681a47ae32SBram Moolenaar /*
691a47ae32SBram Moolenaar * Add a user function to the execution stack.
701a47ae32SBram Moolenaar */
71c620c055SBram Moolenaar estack_T *
estack_push_ufunc(ufunc_T * ufunc,long lnum)7225e0f586SBram Moolenaar estack_push_ufunc(ufunc_T *ufunc, long lnum)
731a47ae32SBram Moolenaar {
7425e0f586SBram Moolenaar estack_T *entry = estack_push(ETYPE_UFUNC,
751a47ae32SBram Moolenaar ufunc->uf_name_exp != NULL
761a47ae32SBram Moolenaar ? ufunc->uf_name_exp : ufunc->uf_name, lnum);
771a47ae32SBram Moolenaar if (entry != NULL)
781a47ae32SBram Moolenaar entry->es_info.ufunc = ufunc;
79c620c055SBram Moolenaar return entry;
801a47ae32SBram Moolenaar }
8125e0f586SBram Moolenaar
8225e0f586SBram Moolenaar /*
8325e0f586SBram Moolenaar * Return TRUE if "ufunc" with "lnum" is already at the top of the exe stack.
8425e0f586SBram Moolenaar */
8525e0f586SBram Moolenaar int
estack_top_is_ufunc(ufunc_T * ufunc,long lnum)8625e0f586SBram Moolenaar estack_top_is_ufunc(ufunc_T *ufunc, long lnum)
8725e0f586SBram Moolenaar {
8825e0f586SBram Moolenaar estack_T *entry;
8925e0f586SBram Moolenaar
9025e0f586SBram Moolenaar if (exestack.ga_len == 0)
9125e0f586SBram Moolenaar return FALSE;
9225e0f586SBram Moolenaar entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
9325e0f586SBram Moolenaar return entry->es_type == ETYPE_UFUNC
9425e0f586SBram Moolenaar && STRCMP( entry->es_name, ufunc->uf_name_exp != NULL
9525e0f586SBram Moolenaar ? ufunc->uf_name_exp : ufunc->uf_name) == 0
9625e0f586SBram Moolenaar && entry->es_lnum == lnum;
9725e0f586SBram Moolenaar }
9809d4640fSBram Moolenaar #endif
991a47ae32SBram Moolenaar
1001a47ae32SBram Moolenaar /*
101c620c055SBram Moolenaar * Take an item off of the execution stack and return it.
1021a47ae32SBram Moolenaar */
103c620c055SBram Moolenaar estack_T *
estack_pop(void)1041a47ae32SBram Moolenaar estack_pop(void)
1051a47ae32SBram Moolenaar {
106c620c055SBram Moolenaar if (exestack.ga_len == 0)
107c620c055SBram Moolenaar return NULL;
1081a47ae32SBram Moolenaar --exestack.ga_len;
109c620c055SBram Moolenaar return ((estack_T *)exestack.ga_data) + exestack.ga_len;
1101a47ae32SBram Moolenaar }
1111a47ae32SBram Moolenaar
1121a47ae32SBram Moolenaar /*
1131a47ae32SBram Moolenaar * Get the current value for <sfile> in allocated memory.
1144f25b1abSBram Moolenaar * "which" is ESTACK_SFILE for <sfile> and ESTACK_STACK for <stack>.
1151a47ae32SBram Moolenaar */
1161a47ae32SBram Moolenaar char_u *
estack_sfile(estack_arg_T which UNUSED)1174f25b1abSBram Moolenaar estack_sfile(estack_arg_T which UNUSED)
1181a47ae32SBram Moolenaar {
11985b09576SBram Moolenaar estack_T *entry;
12085b09576SBram Moolenaar #ifdef FEAT_EVAL
121a5d0423fSBram Moolenaar garray_T ga;
1224d7a248bSBram Moolenaar size_t len;
1231a47ae32SBram Moolenaar int idx;
124a5d0423fSBram Moolenaar etype_T last_type = ETYPE_SCRIPT;
125a5d0423fSBram Moolenaar char *type_name;
12685b09576SBram Moolenaar #endif
1271a47ae32SBram Moolenaar
1281a47ae32SBram Moolenaar entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
129a5d0423fSBram Moolenaar #ifdef FEAT_EVAL
1304f25b1abSBram Moolenaar if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC)
131a5d0423fSBram Moolenaar #endif
132a5d0423fSBram Moolenaar {
1331a47ae32SBram Moolenaar if (entry->es_name == NULL)
1341a47ae32SBram Moolenaar return NULL;
1351a47ae32SBram Moolenaar return vim_strsave(entry->es_name);
136a5d0423fSBram Moolenaar }
13709d4640fSBram Moolenaar #ifdef FEAT_EVAL
138a5d0423fSBram Moolenaar // Give information about each stack entry up to the root.
1391a47ae32SBram Moolenaar // For a function we compose the call stack, as it was done in the past:
1401a47ae32SBram Moolenaar // "function One[123]..Two[456]..Three"
141a5d0423fSBram Moolenaar ga_init2(&ga, sizeof(char), 100);
142a5d0423fSBram Moolenaar for (idx = 0; idx < exestack.ga_len; ++idx)
1431a47ae32SBram Moolenaar {
1441a47ae32SBram Moolenaar entry = ((estack_T *)exestack.ga_data) + idx;
145a5d0423fSBram Moolenaar if (entry->es_name != NULL)
1461a47ae32SBram Moolenaar {
1474f25b1abSBram Moolenaar long lnum = 0;
148a810db3fSBram Moolenaar char *dots;
1494f25b1abSBram Moolenaar
150a5d0423fSBram Moolenaar len = STRLEN(entry->es_name) + 15;
151a5d0423fSBram Moolenaar type_name = "";
152a5d0423fSBram Moolenaar if (entry->es_type != last_type)
153a5d0423fSBram Moolenaar {
154a5d0423fSBram Moolenaar switch (entry->es_type)
155a5d0423fSBram Moolenaar {
156a5d0423fSBram Moolenaar case ETYPE_SCRIPT: type_name = "script "; break;
157a5d0423fSBram Moolenaar case ETYPE_UFUNC: type_name = "function "; break;
158a5d0423fSBram Moolenaar default: type_name = ""; break;
1591a47ae32SBram Moolenaar }
160a5d0423fSBram Moolenaar last_type = entry->es_type;
161a5d0423fSBram Moolenaar }
162a5d0423fSBram Moolenaar len += STRLEN(type_name);
163d3bb6a82SBram Moolenaar if (ga_grow(&ga, (int)len) == FAIL)
164a5d0423fSBram Moolenaar break;
1654f25b1abSBram Moolenaar if (idx == exestack.ga_len - 1)
1664f25b1abSBram Moolenaar lnum = which == ESTACK_STACK ? SOURCING_LNUM : 0;
1674f25b1abSBram Moolenaar else
1684f25b1abSBram Moolenaar lnum = entry->es_lnum;
169a810db3fSBram Moolenaar dots = idx == exestack.ga_len - 1 ? "" : "..";
1704f25b1abSBram Moolenaar if (lnum == 0)
1714f25b1abSBram Moolenaar // For the bottom entry of <sfile>: do not add the line number,
1724f25b1abSBram Moolenaar // it is used in <slnum>. Also leave it out when the number is
1734f25b1abSBram Moolenaar // not set.
174d3bb6a82SBram Moolenaar vim_snprintf((char *)ga.ga_data + ga.ga_len, len, "%s%s%s",
175a810db3fSBram Moolenaar type_name, entry->es_name, dots);
176a5d0423fSBram Moolenaar else
177a810db3fSBram Moolenaar vim_snprintf((char *)ga.ga_data + ga.ga_len, len, "%s%s[%ld]%s",
178a810db3fSBram Moolenaar type_name, entry->es_name, lnum, dots);
179d3bb6a82SBram Moolenaar ga.ga_len += (int)STRLEN((char *)ga.ga_data + ga.ga_len);
180a5d0423fSBram Moolenaar }
1811a47ae32SBram Moolenaar }
1821a47ae32SBram Moolenaar
183a5d0423fSBram Moolenaar return (char_u *)ga.ga_data;
18409d4640fSBram Moolenaar #endif
1851a47ae32SBram Moolenaar }
1861a47ae32SBram Moolenaar
1871a47ae32SBram Moolenaar /*
188307c5a5bSBram Moolenaar * ":runtime [what] {name}"
189307c5a5bSBram Moolenaar */
190307c5a5bSBram Moolenaar void
ex_runtime(exarg_T * eap)191307c5a5bSBram Moolenaar ex_runtime(exarg_T *eap)
192307c5a5bSBram Moolenaar {
193307c5a5bSBram Moolenaar char_u *arg = eap->arg;
194307c5a5bSBram Moolenaar char_u *p = skiptowhite(arg);
195307c5a5bSBram Moolenaar int len = (int)(p - arg);
196307c5a5bSBram Moolenaar int flags = eap->forceit ? DIP_ALL : 0;
197307c5a5bSBram Moolenaar
198307c5a5bSBram Moolenaar if (STRNCMP(arg, "START", len) == 0)
199307c5a5bSBram Moolenaar {
200307c5a5bSBram Moolenaar flags += DIP_START + DIP_NORTP;
201307c5a5bSBram Moolenaar arg = skipwhite(arg + len);
202307c5a5bSBram Moolenaar }
203307c5a5bSBram Moolenaar else if (STRNCMP(arg, "OPT", len) == 0)
204307c5a5bSBram Moolenaar {
205307c5a5bSBram Moolenaar flags += DIP_OPT + DIP_NORTP;
206307c5a5bSBram Moolenaar arg = skipwhite(arg + len);
207307c5a5bSBram Moolenaar }
208307c5a5bSBram Moolenaar else if (STRNCMP(arg, "PACK", len) == 0)
209307c5a5bSBram Moolenaar {
210307c5a5bSBram Moolenaar flags += DIP_START + DIP_OPT + DIP_NORTP;
211307c5a5bSBram Moolenaar arg = skipwhite(arg + len);
212307c5a5bSBram Moolenaar }
213307c5a5bSBram Moolenaar else if (STRNCMP(arg, "ALL", len) == 0)
214307c5a5bSBram Moolenaar {
215307c5a5bSBram Moolenaar flags += DIP_START + DIP_OPT;
216307c5a5bSBram Moolenaar arg = skipwhite(arg + len);
217307c5a5bSBram Moolenaar }
218307c5a5bSBram Moolenaar
219307c5a5bSBram Moolenaar source_runtime(arg, flags);
220307c5a5bSBram Moolenaar }
221307c5a5bSBram Moolenaar
222307c5a5bSBram Moolenaar static void
source_callback(char_u * fname,void * cookie)2238a7d6542SBram Moolenaar source_callback(char_u *fname, void *cookie)
224307c5a5bSBram Moolenaar {
2258a7d6542SBram Moolenaar (void)do_source(fname, FALSE, DOSO_NONE, cookie);
226307c5a5bSBram Moolenaar }
227307c5a5bSBram Moolenaar
228307c5a5bSBram Moolenaar /*
229307c5a5bSBram Moolenaar * Find the file "name" in all directories in "path" and invoke
230307c5a5bSBram Moolenaar * "callback(fname, cookie)".
231307c5a5bSBram Moolenaar * "name" can contain wildcards.
232307c5a5bSBram Moolenaar * When "flags" has DIP_ALL: source all files, otherwise only the first one.
233307c5a5bSBram Moolenaar * When "flags" has DIP_DIR: find directories instead of files.
234307c5a5bSBram Moolenaar * When "flags" has DIP_ERR: give an error message if there is no match.
235307c5a5bSBram Moolenaar *
236307c5a5bSBram Moolenaar * return FAIL when no file could be sourced, OK otherwise.
237307c5a5bSBram Moolenaar */
238307c5a5bSBram Moolenaar int
do_in_path(char_u * path,char_u * name,int flags,void (* callback)(char_u * fname,void * ck),void * cookie)239307c5a5bSBram Moolenaar do_in_path(
240307c5a5bSBram Moolenaar char_u *path,
241307c5a5bSBram Moolenaar char_u *name,
242307c5a5bSBram Moolenaar int flags,
243307c5a5bSBram Moolenaar void (*callback)(char_u *fname, void *ck),
244307c5a5bSBram Moolenaar void *cookie)
245307c5a5bSBram Moolenaar {
246307c5a5bSBram Moolenaar char_u *rtp;
247307c5a5bSBram Moolenaar char_u *np;
248307c5a5bSBram Moolenaar char_u *buf;
249307c5a5bSBram Moolenaar char_u *rtp_copy;
250307c5a5bSBram Moolenaar char_u *tail;
251307c5a5bSBram Moolenaar int num_files;
252307c5a5bSBram Moolenaar char_u **files;
253307c5a5bSBram Moolenaar int i;
254307c5a5bSBram Moolenaar int did_one = FALSE;
255307c5a5bSBram Moolenaar #ifdef AMIGA
256307c5a5bSBram Moolenaar struct Process *proc = (struct Process *)FindTask(0L);
257307c5a5bSBram Moolenaar APTR save_winptr = proc->pr_WindowPtr;
258307c5a5bSBram Moolenaar
259307c5a5bSBram Moolenaar // Avoid a requester here for a volume that doesn't exist.
260307c5a5bSBram Moolenaar proc->pr_WindowPtr = (APTR)-1L;
261307c5a5bSBram Moolenaar #endif
262307c5a5bSBram Moolenaar
263307c5a5bSBram Moolenaar // Make a copy of 'runtimepath'. Invoking the callback may change the
264307c5a5bSBram Moolenaar // value.
265307c5a5bSBram Moolenaar rtp_copy = vim_strsave(path);
266307c5a5bSBram Moolenaar buf = alloc(MAXPATHL);
267307c5a5bSBram Moolenaar if (buf != NULL && rtp_copy != NULL)
268307c5a5bSBram Moolenaar {
269647a530bSBram Moolenaar if (p_verbose > 10 && name != NULL)
270307c5a5bSBram Moolenaar {
271307c5a5bSBram Moolenaar verbose_enter();
272307c5a5bSBram Moolenaar smsg(_("Searching for \"%s\" in \"%s\""),
273307c5a5bSBram Moolenaar (char *)name, (char *)path);
274307c5a5bSBram Moolenaar verbose_leave();
275307c5a5bSBram Moolenaar }
276307c5a5bSBram Moolenaar
277307c5a5bSBram Moolenaar // Loop over all entries in 'runtimepath'.
278307c5a5bSBram Moolenaar rtp = rtp_copy;
279307c5a5bSBram Moolenaar while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
280307c5a5bSBram Moolenaar {
281307c5a5bSBram Moolenaar size_t buflen;
282307c5a5bSBram Moolenaar
283307c5a5bSBram Moolenaar // Copy the path from 'runtimepath' to buf[].
284307c5a5bSBram Moolenaar copy_option_part(&rtp, buf, MAXPATHL, ",");
285307c5a5bSBram Moolenaar buflen = STRLEN(buf);
286307c5a5bSBram Moolenaar
287307c5a5bSBram Moolenaar // Skip after or non-after directories.
288307c5a5bSBram Moolenaar if (flags & (DIP_NOAFTER | DIP_AFTER))
289307c5a5bSBram Moolenaar {
290307c5a5bSBram Moolenaar int is_after = buflen >= 5
291307c5a5bSBram Moolenaar && STRCMP(buf + buflen - 5, "after") == 0;
292307c5a5bSBram Moolenaar
293307c5a5bSBram Moolenaar if ((is_after && (flags & DIP_NOAFTER))
294307c5a5bSBram Moolenaar || (!is_after && (flags & DIP_AFTER)))
295307c5a5bSBram Moolenaar continue;
296307c5a5bSBram Moolenaar }
297307c5a5bSBram Moolenaar
298307c5a5bSBram Moolenaar if (name == NULL)
299307c5a5bSBram Moolenaar {
300307c5a5bSBram Moolenaar (*callback)(buf, (void *) &cookie);
301307c5a5bSBram Moolenaar if (!did_one)
302307c5a5bSBram Moolenaar did_one = (cookie == NULL);
303307c5a5bSBram Moolenaar }
304307c5a5bSBram Moolenaar else if (buflen + STRLEN(name) + 2 < MAXPATHL)
305307c5a5bSBram Moolenaar {
306307c5a5bSBram Moolenaar add_pathsep(buf);
307307c5a5bSBram Moolenaar tail = buf + STRLEN(buf);
308307c5a5bSBram Moolenaar
309307c5a5bSBram Moolenaar // Loop over all patterns in "name"
310307c5a5bSBram Moolenaar np = name;
311307c5a5bSBram Moolenaar while (*np != NUL && ((flags & DIP_ALL) || !did_one))
312307c5a5bSBram Moolenaar {
313307c5a5bSBram Moolenaar // Append the pattern from "name" to buf[].
314307c5a5bSBram Moolenaar copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
315307c5a5bSBram Moolenaar "\t ");
316307c5a5bSBram Moolenaar
317647a530bSBram Moolenaar if (p_verbose > 10)
318307c5a5bSBram Moolenaar {
319307c5a5bSBram Moolenaar verbose_enter();
320307c5a5bSBram Moolenaar smsg(_("Searching for \"%s\""), buf);
321307c5a5bSBram Moolenaar verbose_leave();
322307c5a5bSBram Moolenaar }
323307c5a5bSBram Moolenaar
324307c5a5bSBram Moolenaar // Expand wildcards, invoke the callback for each match.
325307c5a5bSBram Moolenaar if (gen_expand_wildcards(1, &buf, &num_files, &files,
326307c5a5bSBram Moolenaar (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
327307c5a5bSBram Moolenaar {
328307c5a5bSBram Moolenaar for (i = 0; i < num_files; ++i)
329307c5a5bSBram Moolenaar {
330307c5a5bSBram Moolenaar (*callback)(files[i], cookie);
331307c5a5bSBram Moolenaar did_one = TRUE;
332307c5a5bSBram Moolenaar if (!(flags & DIP_ALL))
333307c5a5bSBram Moolenaar break;
334307c5a5bSBram Moolenaar }
335307c5a5bSBram Moolenaar FreeWild(num_files, files);
336307c5a5bSBram Moolenaar }
337307c5a5bSBram Moolenaar }
338307c5a5bSBram Moolenaar }
339307c5a5bSBram Moolenaar }
340307c5a5bSBram Moolenaar }
341307c5a5bSBram Moolenaar vim_free(buf);
342307c5a5bSBram Moolenaar vim_free(rtp_copy);
343307c5a5bSBram Moolenaar if (!did_one && name != NULL)
344307c5a5bSBram Moolenaar {
345307c5a5bSBram Moolenaar char *basepath = path == p_rtp ? "runtimepath" : "packpath";
346307c5a5bSBram Moolenaar
347307c5a5bSBram Moolenaar if (flags & DIP_ERR)
348307c5a5bSBram Moolenaar semsg(_(e_dirnotf), basepath, name);
349307c5a5bSBram Moolenaar else if (p_verbose > 0)
350307c5a5bSBram Moolenaar {
351307c5a5bSBram Moolenaar verbose_enter();
352307c5a5bSBram Moolenaar smsg(_("not found in '%s': \"%s\""), basepath, name);
353307c5a5bSBram Moolenaar verbose_leave();
354307c5a5bSBram Moolenaar }
355307c5a5bSBram Moolenaar }
356307c5a5bSBram Moolenaar
357307c5a5bSBram Moolenaar #ifdef AMIGA
358307c5a5bSBram Moolenaar proc->pr_WindowPtr = save_winptr;
359307c5a5bSBram Moolenaar #endif
360307c5a5bSBram Moolenaar
361307c5a5bSBram Moolenaar return did_one ? OK : FAIL;
362307c5a5bSBram Moolenaar }
363307c5a5bSBram Moolenaar
364307c5a5bSBram Moolenaar /*
365307c5a5bSBram Moolenaar * Find "name" in "path". When found, invoke the callback function for
366307c5a5bSBram Moolenaar * it: callback(fname, "cookie")
367307c5a5bSBram Moolenaar * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
368307c5a5bSBram Moolenaar * one is used.
369307c5a5bSBram Moolenaar * Returns OK when at least one match found, FAIL otherwise.
370307c5a5bSBram Moolenaar *
371307c5a5bSBram Moolenaar * If "name" is NULL calls callback for each entry in "path". Cookie is
372307c5a5bSBram Moolenaar * passed by reference in this case, setting it to NULL indicates that callback
373307c5a5bSBram Moolenaar * has done its job.
374307c5a5bSBram Moolenaar */
375307c5a5bSBram Moolenaar static int
do_in_path_and_pp(char_u * path,char_u * name,int flags,void (* callback)(char_u * fname,void * ck),void * cookie)376307c5a5bSBram Moolenaar do_in_path_and_pp(
377307c5a5bSBram Moolenaar char_u *path,
378307c5a5bSBram Moolenaar char_u *name,
379307c5a5bSBram Moolenaar int flags,
380307c5a5bSBram Moolenaar void (*callback)(char_u *fname, void *ck),
381307c5a5bSBram Moolenaar void *cookie)
382307c5a5bSBram Moolenaar {
383307c5a5bSBram Moolenaar int done = FAIL;
384307c5a5bSBram Moolenaar char_u *s;
385307c5a5bSBram Moolenaar int len;
386307c5a5bSBram Moolenaar char *start_dir = "pack/*/start/*/%s";
387307c5a5bSBram Moolenaar char *opt_dir = "pack/*/opt/*/%s";
388307c5a5bSBram Moolenaar
389307c5a5bSBram Moolenaar if ((flags & DIP_NORTP) == 0)
390307c5a5bSBram Moolenaar done = do_in_path(path, name, flags, callback, cookie);
391307c5a5bSBram Moolenaar
392307c5a5bSBram Moolenaar if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
393307c5a5bSBram Moolenaar {
394307c5a5bSBram Moolenaar len = (int)(STRLEN(start_dir) + STRLEN(name));
395307c5a5bSBram Moolenaar s = alloc(len);
396307c5a5bSBram Moolenaar if (s == NULL)
397307c5a5bSBram Moolenaar return FAIL;
398307c5a5bSBram Moolenaar vim_snprintf((char *)s, len, start_dir, name);
399307c5a5bSBram Moolenaar done = do_in_path(p_pp, s, flags, callback, cookie);
400307c5a5bSBram Moolenaar vim_free(s);
401307c5a5bSBram Moolenaar }
402307c5a5bSBram Moolenaar
403307c5a5bSBram Moolenaar if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
404307c5a5bSBram Moolenaar {
405307c5a5bSBram Moolenaar len = (int)(STRLEN(opt_dir) + STRLEN(name));
406307c5a5bSBram Moolenaar s = alloc(len);
407307c5a5bSBram Moolenaar if (s == NULL)
408307c5a5bSBram Moolenaar return FAIL;
409307c5a5bSBram Moolenaar vim_snprintf((char *)s, len, opt_dir, name);
410307c5a5bSBram Moolenaar done = do_in_path(p_pp, s, flags, callback, cookie);
411307c5a5bSBram Moolenaar vim_free(s);
412307c5a5bSBram Moolenaar }
413307c5a5bSBram Moolenaar
414307c5a5bSBram Moolenaar return done;
415307c5a5bSBram Moolenaar }
416307c5a5bSBram Moolenaar
417307c5a5bSBram Moolenaar /*
418307c5a5bSBram Moolenaar * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
419307c5a5bSBram Moolenaar */
420307c5a5bSBram Moolenaar int
do_in_runtimepath(char_u * name,int flags,void (* callback)(char_u * fname,void * ck),void * cookie)421307c5a5bSBram Moolenaar do_in_runtimepath(
422307c5a5bSBram Moolenaar char_u *name,
423307c5a5bSBram Moolenaar int flags,
424307c5a5bSBram Moolenaar void (*callback)(char_u *fname, void *ck),
425307c5a5bSBram Moolenaar void *cookie)
426307c5a5bSBram Moolenaar {
427307c5a5bSBram Moolenaar return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
428307c5a5bSBram Moolenaar }
429307c5a5bSBram Moolenaar
430307c5a5bSBram Moolenaar /*
431307c5a5bSBram Moolenaar * Source the file "name" from all directories in 'runtimepath'.
432307c5a5bSBram Moolenaar * "name" can contain wildcards.
433307c5a5bSBram Moolenaar * When "flags" has DIP_ALL: source all files, otherwise only the first one.
434307c5a5bSBram Moolenaar *
435307c5a5bSBram Moolenaar * return FAIL when no file could be sourced, OK otherwise.
436307c5a5bSBram Moolenaar */
437307c5a5bSBram Moolenaar int
source_runtime(char_u * name,int flags)438307c5a5bSBram Moolenaar source_runtime(char_u *name, int flags)
439307c5a5bSBram Moolenaar {
4408a7d6542SBram Moolenaar return source_in_path(p_rtp, name, flags, NULL);
441307c5a5bSBram Moolenaar }
442307c5a5bSBram Moolenaar
443307c5a5bSBram Moolenaar /*
444307c5a5bSBram Moolenaar * Just like source_runtime(), but use "path" instead of 'runtimepath'.
445307c5a5bSBram Moolenaar */
446307c5a5bSBram Moolenaar int
source_in_path(char_u * path,char_u * name,int flags,int * ret_sid)4478a7d6542SBram Moolenaar source_in_path(char_u *path, char_u *name, int flags, int *ret_sid)
448307c5a5bSBram Moolenaar {
4498a7d6542SBram Moolenaar return do_in_path_and_pp(path, name, flags, source_callback, ret_sid);
450307c5a5bSBram Moolenaar }
451307c5a5bSBram Moolenaar
452307c5a5bSBram Moolenaar
453307c5a5bSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
454307c5a5bSBram Moolenaar
455307c5a5bSBram Moolenaar /*
456307c5a5bSBram Moolenaar * Expand wildcards in "pat" and invoke do_source() for each match.
457307c5a5bSBram Moolenaar */
458307c5a5bSBram Moolenaar static void
source_all_matches(char_u * pat)459307c5a5bSBram Moolenaar source_all_matches(char_u *pat)
460307c5a5bSBram Moolenaar {
461307c5a5bSBram Moolenaar int num_files;
462307c5a5bSBram Moolenaar char_u **files;
463307c5a5bSBram Moolenaar int i;
464307c5a5bSBram Moolenaar
465307c5a5bSBram Moolenaar if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
466307c5a5bSBram Moolenaar {
467307c5a5bSBram Moolenaar for (i = 0; i < num_files; ++i)
4688a7d6542SBram Moolenaar (void)do_source(files[i], FALSE, DOSO_NONE, NULL);
469307c5a5bSBram Moolenaar FreeWild(num_files, files);
470307c5a5bSBram Moolenaar }
471307c5a5bSBram Moolenaar }
472307c5a5bSBram Moolenaar
473307c5a5bSBram Moolenaar /*
474307c5a5bSBram Moolenaar * Add the package directory to 'runtimepath'.
475307c5a5bSBram Moolenaar */
476307c5a5bSBram Moolenaar static int
add_pack_dir_to_rtp(char_u * fname)477307c5a5bSBram Moolenaar add_pack_dir_to_rtp(char_u *fname)
478307c5a5bSBram Moolenaar {
479307c5a5bSBram Moolenaar char_u *p4, *p3, *p2, *p1, *p;
480307c5a5bSBram Moolenaar char_u *entry;
481307c5a5bSBram Moolenaar char_u *insp = NULL;
482307c5a5bSBram Moolenaar int c;
483307c5a5bSBram Moolenaar char_u *new_rtp;
484307c5a5bSBram Moolenaar int keep;
485307c5a5bSBram Moolenaar size_t oldlen;
486307c5a5bSBram Moolenaar size_t addlen;
487307c5a5bSBram Moolenaar size_t new_rtp_len;
488307c5a5bSBram Moolenaar char_u *afterdir = NULL;
489307c5a5bSBram Moolenaar size_t afterlen = 0;
490307c5a5bSBram Moolenaar char_u *after_insp = NULL;
491307c5a5bSBram Moolenaar char_u *ffname = NULL;
492307c5a5bSBram Moolenaar size_t fname_len;
493307c5a5bSBram Moolenaar char_u *buf = NULL;
494307c5a5bSBram Moolenaar char_u *rtp_ffname;
495307c5a5bSBram Moolenaar int match;
496307c5a5bSBram Moolenaar int retval = FAIL;
497307c5a5bSBram Moolenaar
498307c5a5bSBram Moolenaar p4 = p3 = p2 = p1 = get_past_head(fname);
499307c5a5bSBram Moolenaar for (p = p1; *p; MB_PTR_ADV(p))
500307c5a5bSBram Moolenaar if (vim_ispathsep_nocolon(*p))
501307c5a5bSBram Moolenaar {
502307c5a5bSBram Moolenaar p4 = p3; p3 = p2; p2 = p1; p1 = p;
503307c5a5bSBram Moolenaar }
504307c5a5bSBram Moolenaar
505307c5a5bSBram Moolenaar // now we have:
506307c5a5bSBram Moolenaar // rtp/pack/name/start/name
507307c5a5bSBram Moolenaar // p4 p3 p2 p1
508307c5a5bSBram Moolenaar //
509307c5a5bSBram Moolenaar // find the part up to "pack" in 'runtimepath'
510307c5a5bSBram Moolenaar c = *++p4; // append pathsep in order to expand symlink
511307c5a5bSBram Moolenaar *p4 = NUL;
512307c5a5bSBram Moolenaar ffname = fix_fname(fname);
513307c5a5bSBram Moolenaar *p4 = c;
514307c5a5bSBram Moolenaar if (ffname == NULL)
515307c5a5bSBram Moolenaar return FAIL;
516307c5a5bSBram Moolenaar
517307c5a5bSBram Moolenaar // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences.
518307c5a5bSBram Moolenaar // Also stop at the first "after" directory.
519307c5a5bSBram Moolenaar fname_len = STRLEN(ffname);
520307c5a5bSBram Moolenaar buf = alloc(MAXPATHL);
521307c5a5bSBram Moolenaar if (buf == NULL)
522307c5a5bSBram Moolenaar goto theend;
523307c5a5bSBram Moolenaar for (entry = p_rtp; *entry != NUL; )
524307c5a5bSBram Moolenaar {
525307c5a5bSBram Moolenaar char_u *cur_entry = entry;
526307c5a5bSBram Moolenaar
527307c5a5bSBram Moolenaar copy_option_part(&entry, buf, MAXPATHL, ",");
528307c5a5bSBram Moolenaar if (insp == NULL)
529307c5a5bSBram Moolenaar {
530307c5a5bSBram Moolenaar add_pathsep(buf);
531307c5a5bSBram Moolenaar rtp_ffname = fix_fname(buf);
532307c5a5bSBram Moolenaar if (rtp_ffname == NULL)
533307c5a5bSBram Moolenaar goto theend;
534307c5a5bSBram Moolenaar match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
535307c5a5bSBram Moolenaar vim_free(rtp_ffname);
536307c5a5bSBram Moolenaar if (match)
537307c5a5bSBram Moolenaar // Insert "ffname" after this entry (and comma).
538307c5a5bSBram Moolenaar insp = entry;
539307c5a5bSBram Moolenaar }
540307c5a5bSBram Moolenaar
541307c5a5bSBram Moolenaar if ((p = (char_u *)strstr((char *)buf, "after")) != NULL
542307c5a5bSBram Moolenaar && p > buf
543307c5a5bSBram Moolenaar && vim_ispathsep(p[-1])
544307c5a5bSBram Moolenaar && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','))
545307c5a5bSBram Moolenaar {
546307c5a5bSBram Moolenaar if (insp == NULL)
547307c5a5bSBram Moolenaar // Did not find "ffname" before the first "after" directory,
548307c5a5bSBram Moolenaar // insert it before this entry.
549307c5a5bSBram Moolenaar insp = cur_entry;
550307c5a5bSBram Moolenaar after_insp = cur_entry;
551307c5a5bSBram Moolenaar break;
552307c5a5bSBram Moolenaar }
553307c5a5bSBram Moolenaar }
554307c5a5bSBram Moolenaar
555307c5a5bSBram Moolenaar if (insp == NULL)
556307c5a5bSBram Moolenaar // Both "fname" and "after" not found, append at the end.
557307c5a5bSBram Moolenaar insp = p_rtp + STRLEN(p_rtp);
558307c5a5bSBram Moolenaar
559307c5a5bSBram Moolenaar // check if rtp/pack/name/start/name/after exists
560307c5a5bSBram Moolenaar afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
561307c5a5bSBram Moolenaar if (afterdir != NULL && mch_isdir(afterdir))
562307c5a5bSBram Moolenaar afterlen = STRLEN(afterdir) + 1; // add one for comma
563307c5a5bSBram Moolenaar
564307c5a5bSBram Moolenaar oldlen = STRLEN(p_rtp);
565307c5a5bSBram Moolenaar addlen = STRLEN(fname) + 1; // add one for comma
566307c5a5bSBram Moolenaar new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
567307c5a5bSBram Moolenaar if (new_rtp == NULL)
568307c5a5bSBram Moolenaar goto theend;
569307c5a5bSBram Moolenaar
570307c5a5bSBram Moolenaar // We now have 'rtp' parts: {keep}{keep_after}{rest}.
571307c5a5bSBram Moolenaar // Create new_rtp, first: {keep},{fname}
572307c5a5bSBram Moolenaar keep = (int)(insp - p_rtp);
573307c5a5bSBram Moolenaar mch_memmove(new_rtp, p_rtp, keep);
574307c5a5bSBram Moolenaar new_rtp_len = keep;
575307c5a5bSBram Moolenaar if (*insp == NUL)
576307c5a5bSBram Moolenaar new_rtp[new_rtp_len++] = ','; // add comma before
577307c5a5bSBram Moolenaar mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
578307c5a5bSBram Moolenaar new_rtp_len += addlen - 1;
579307c5a5bSBram Moolenaar if (*insp != NUL)
580307c5a5bSBram Moolenaar new_rtp[new_rtp_len++] = ','; // add comma after
581307c5a5bSBram Moolenaar
582307c5a5bSBram Moolenaar if (afterlen > 0 && after_insp != NULL)
583307c5a5bSBram Moolenaar {
584307c5a5bSBram Moolenaar int keep_after = (int)(after_insp - p_rtp);
585307c5a5bSBram Moolenaar
586307c5a5bSBram Moolenaar // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
587307c5a5bSBram Moolenaar mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
588307c5a5bSBram Moolenaar keep_after - keep);
589307c5a5bSBram Moolenaar new_rtp_len += keep_after - keep;
590307c5a5bSBram Moolenaar mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
591307c5a5bSBram Moolenaar new_rtp_len += afterlen - 1;
592307c5a5bSBram Moolenaar new_rtp[new_rtp_len++] = ',';
593307c5a5bSBram Moolenaar keep = keep_after;
594307c5a5bSBram Moolenaar }
595307c5a5bSBram Moolenaar
596307c5a5bSBram Moolenaar if (p_rtp[keep] != NUL)
597307c5a5bSBram Moolenaar // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
598307c5a5bSBram Moolenaar mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
599307c5a5bSBram Moolenaar else
600307c5a5bSBram Moolenaar new_rtp[new_rtp_len] = NUL;
601307c5a5bSBram Moolenaar
602307c5a5bSBram Moolenaar if (afterlen > 0 && after_insp == NULL)
603307c5a5bSBram Moolenaar {
604307c5a5bSBram Moolenaar // Append afterdir when "after" was not found:
605307c5a5bSBram Moolenaar // {keep},{fname}{rest},{afterdir}
606307c5a5bSBram Moolenaar STRCAT(new_rtp, ",");
607307c5a5bSBram Moolenaar STRCAT(new_rtp, afterdir);
608307c5a5bSBram Moolenaar }
609307c5a5bSBram Moolenaar
610307c5a5bSBram Moolenaar set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
611307c5a5bSBram Moolenaar vim_free(new_rtp);
612307c5a5bSBram Moolenaar retval = OK;
613307c5a5bSBram Moolenaar
614307c5a5bSBram Moolenaar theend:
615307c5a5bSBram Moolenaar vim_free(buf);
616307c5a5bSBram Moolenaar vim_free(ffname);
617307c5a5bSBram Moolenaar vim_free(afterdir);
618307c5a5bSBram Moolenaar return retval;
619307c5a5bSBram Moolenaar }
620307c5a5bSBram Moolenaar
621307c5a5bSBram Moolenaar /*
622307c5a5bSBram Moolenaar * Load scripts in "plugin" and "ftdetect" directories of the package.
623307c5a5bSBram Moolenaar */
624307c5a5bSBram Moolenaar static int
load_pack_plugin(char_u * fname)625307c5a5bSBram Moolenaar load_pack_plugin(char_u *fname)
626307c5a5bSBram Moolenaar {
627307c5a5bSBram Moolenaar static char *plugpat = "%s/plugin/**/*.vim";
628307c5a5bSBram Moolenaar static char *ftpat = "%s/ftdetect/*.vim";
629307c5a5bSBram Moolenaar int len;
630307c5a5bSBram Moolenaar char_u *ffname = fix_fname(fname);
631307c5a5bSBram Moolenaar char_u *pat = NULL;
632307c5a5bSBram Moolenaar int retval = FAIL;
633307c5a5bSBram Moolenaar
634307c5a5bSBram Moolenaar if (ffname == NULL)
635307c5a5bSBram Moolenaar return FAIL;
636307c5a5bSBram Moolenaar len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
637307c5a5bSBram Moolenaar pat = alloc(len);
638307c5a5bSBram Moolenaar if (pat == NULL)
639307c5a5bSBram Moolenaar goto theend;
640307c5a5bSBram Moolenaar vim_snprintf((char *)pat, len, plugpat, ffname);
641307c5a5bSBram Moolenaar source_all_matches(pat);
642307c5a5bSBram Moolenaar
643307c5a5bSBram Moolenaar {
644307c5a5bSBram Moolenaar char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
645307c5a5bSBram Moolenaar
646307c5a5bSBram Moolenaar // If runtime/filetype.vim wasn't loaded yet, the scripts will be
647307c5a5bSBram Moolenaar // found when it loads.
648307c5a5bSBram Moolenaar if (cmd != NULL && eval_to_number(cmd) > 0)
649307c5a5bSBram Moolenaar {
650307c5a5bSBram Moolenaar do_cmdline_cmd((char_u *)"augroup filetypedetect");
651307c5a5bSBram Moolenaar vim_snprintf((char *)pat, len, ftpat, ffname);
652307c5a5bSBram Moolenaar source_all_matches(pat);
653307c5a5bSBram Moolenaar do_cmdline_cmd((char_u *)"augroup END");
654307c5a5bSBram Moolenaar }
655307c5a5bSBram Moolenaar vim_free(cmd);
656307c5a5bSBram Moolenaar }
657307c5a5bSBram Moolenaar vim_free(pat);
658307c5a5bSBram Moolenaar retval = OK;
659307c5a5bSBram Moolenaar
660307c5a5bSBram Moolenaar theend:
661307c5a5bSBram Moolenaar vim_free(ffname);
662307c5a5bSBram Moolenaar return retval;
663307c5a5bSBram Moolenaar }
664307c5a5bSBram Moolenaar
665307c5a5bSBram Moolenaar // used for "cookie" of add_pack_plugin()
666307c5a5bSBram Moolenaar static int APP_ADD_DIR;
667307c5a5bSBram Moolenaar static int APP_LOAD;
668307c5a5bSBram Moolenaar static int APP_BOTH;
669307c5a5bSBram Moolenaar
670307c5a5bSBram Moolenaar static void
add_pack_plugin(char_u * fname,void * cookie)671307c5a5bSBram Moolenaar add_pack_plugin(char_u *fname, void *cookie)
672307c5a5bSBram Moolenaar {
673307c5a5bSBram Moolenaar if (cookie != &APP_LOAD)
674307c5a5bSBram Moolenaar {
675307c5a5bSBram Moolenaar char_u *buf = alloc(MAXPATHL);
676307c5a5bSBram Moolenaar char_u *p;
677307c5a5bSBram Moolenaar int found = FALSE;
678307c5a5bSBram Moolenaar
679307c5a5bSBram Moolenaar if (buf == NULL)
680307c5a5bSBram Moolenaar return;
681307c5a5bSBram Moolenaar p = p_rtp;
682307c5a5bSBram Moolenaar while (*p != NUL)
683307c5a5bSBram Moolenaar {
684307c5a5bSBram Moolenaar copy_option_part(&p, buf, MAXPATHL, ",");
685307c5a5bSBram Moolenaar if (pathcmp((char *)buf, (char *)fname, -1) == 0)
686307c5a5bSBram Moolenaar {
687307c5a5bSBram Moolenaar found = TRUE;
688307c5a5bSBram Moolenaar break;
689307c5a5bSBram Moolenaar }
690307c5a5bSBram Moolenaar }
691307c5a5bSBram Moolenaar vim_free(buf);
692307c5a5bSBram Moolenaar if (!found)
693307c5a5bSBram Moolenaar // directory is not yet in 'runtimepath', add it
694307c5a5bSBram Moolenaar if (add_pack_dir_to_rtp(fname) == FAIL)
695307c5a5bSBram Moolenaar return;
696307c5a5bSBram Moolenaar }
697307c5a5bSBram Moolenaar
698307c5a5bSBram Moolenaar if (cookie != &APP_ADD_DIR)
699307c5a5bSBram Moolenaar load_pack_plugin(fname);
700307c5a5bSBram Moolenaar }
701307c5a5bSBram Moolenaar
702307c5a5bSBram Moolenaar /*
703307c5a5bSBram Moolenaar * Add all packages in the "start" directory to 'runtimepath'.
704307c5a5bSBram Moolenaar */
705307c5a5bSBram Moolenaar void
add_pack_start_dirs(void)706307c5a5bSBram Moolenaar add_pack_start_dirs(void)
707307c5a5bSBram Moolenaar {
708307c5a5bSBram Moolenaar do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
709307c5a5bSBram Moolenaar add_pack_plugin, &APP_ADD_DIR);
710307c5a5bSBram Moolenaar }
711307c5a5bSBram Moolenaar
712307c5a5bSBram Moolenaar /*
713307c5a5bSBram Moolenaar * Load plugins from all packages in the "start" directory.
714307c5a5bSBram Moolenaar */
715307c5a5bSBram Moolenaar void
load_start_packages(void)716307c5a5bSBram Moolenaar load_start_packages(void)
717307c5a5bSBram Moolenaar {
718307c5a5bSBram Moolenaar did_source_packages = TRUE;
719307c5a5bSBram Moolenaar do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
720307c5a5bSBram Moolenaar add_pack_plugin, &APP_LOAD);
721307c5a5bSBram Moolenaar }
722307c5a5bSBram Moolenaar
723307c5a5bSBram Moolenaar /*
724307c5a5bSBram Moolenaar * ":packloadall"
725307c5a5bSBram Moolenaar * Find plugins in the package directories and source them.
726307c5a5bSBram Moolenaar */
727307c5a5bSBram Moolenaar void
ex_packloadall(exarg_T * eap)728307c5a5bSBram Moolenaar ex_packloadall(exarg_T *eap)
729307c5a5bSBram Moolenaar {
730307c5a5bSBram Moolenaar if (!did_source_packages || eap->forceit)
731307c5a5bSBram Moolenaar {
732307c5a5bSBram Moolenaar // First do a round to add all directories to 'runtimepath', then load
733307c5a5bSBram Moolenaar // the plugins. This allows for plugins to use an autoload directory
734307c5a5bSBram Moolenaar // of another plugin.
735307c5a5bSBram Moolenaar add_pack_start_dirs();
736307c5a5bSBram Moolenaar load_start_packages();
737307c5a5bSBram Moolenaar }
738307c5a5bSBram Moolenaar }
739307c5a5bSBram Moolenaar
740307c5a5bSBram Moolenaar /*
741307c5a5bSBram Moolenaar * ":packadd[!] {name}"
742307c5a5bSBram Moolenaar */
743307c5a5bSBram Moolenaar void
ex_packadd(exarg_T * eap)744307c5a5bSBram Moolenaar ex_packadd(exarg_T *eap)
745307c5a5bSBram Moolenaar {
746307c5a5bSBram Moolenaar static char *plugpat = "pack/*/%s/%s";
747307c5a5bSBram Moolenaar int len;
748307c5a5bSBram Moolenaar char *pat;
749307c5a5bSBram Moolenaar int round;
750307c5a5bSBram Moolenaar int res = OK;
751307c5a5bSBram Moolenaar
752307c5a5bSBram Moolenaar // Round 1: use "start", round 2: use "opt".
753307c5a5bSBram Moolenaar for (round = 1; round <= 2; ++round)
754307c5a5bSBram Moolenaar {
755307c5a5bSBram Moolenaar // Only look under "start" when loading packages wasn't done yet.
756307c5a5bSBram Moolenaar if (round == 1 && did_source_packages)
757307c5a5bSBram Moolenaar continue;
758307c5a5bSBram Moolenaar
759307c5a5bSBram Moolenaar len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg) + 5;
760307c5a5bSBram Moolenaar pat = alloc(len);
761307c5a5bSBram Moolenaar if (pat == NULL)
762307c5a5bSBram Moolenaar return;
763307c5a5bSBram Moolenaar vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
764307c5a5bSBram Moolenaar // The first round don't give a "not found" error, in the second round
765307c5a5bSBram Moolenaar // only when nothing was found in the first round.
766307c5a5bSBram Moolenaar res = do_in_path(p_pp, (char_u *)pat,
767307c5a5bSBram Moolenaar DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
768307c5a5bSBram Moolenaar add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
769307c5a5bSBram Moolenaar vim_free(pat);
770307c5a5bSBram Moolenaar }
771307c5a5bSBram Moolenaar }
772307c5a5bSBram Moolenaar #endif
773307c5a5bSBram Moolenaar
774307c5a5bSBram Moolenaar /*
77526262f87SBram Moolenaar * Sort "gap" and remove duplicate entries. "gap" is expected to contain a
77626262f87SBram Moolenaar * list of file names in allocated memory.
77726262f87SBram Moolenaar */
77826262f87SBram Moolenaar void
remove_duplicates(garray_T * gap)77926262f87SBram Moolenaar remove_duplicates(garray_T *gap)
78026262f87SBram Moolenaar {
78126262f87SBram Moolenaar int i;
78226262f87SBram Moolenaar int j;
78326262f87SBram Moolenaar char_u **fnames = (char_u **)gap->ga_data;
78426262f87SBram Moolenaar
78526262f87SBram Moolenaar sort_strings(fnames, gap->ga_len);
78626262f87SBram Moolenaar for (i = gap->ga_len - 1; i > 0; --i)
78726262f87SBram Moolenaar if (fnamecmp(fnames[i - 1], fnames[i]) == 0)
78826262f87SBram Moolenaar {
78926262f87SBram Moolenaar vim_free(fnames[i]);
79026262f87SBram Moolenaar for (j = i + 1; j < gap->ga_len; ++j)
79126262f87SBram Moolenaar fnames[j - 1] = fnames[j];
79226262f87SBram Moolenaar --gap->ga_len;
79326262f87SBram Moolenaar }
79426262f87SBram Moolenaar }
79526262f87SBram Moolenaar
79626262f87SBram Moolenaar /*
797307c5a5bSBram Moolenaar * Expand color scheme, compiler or filetype names.
798307c5a5bSBram Moolenaar * Search from 'runtimepath':
799307c5a5bSBram Moolenaar * 'runtimepath'/{dirnames}/{pat}.vim
800307c5a5bSBram Moolenaar * When "flags" has DIP_START: search also from 'start' of 'packpath':
801307c5a5bSBram Moolenaar * 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim
802307c5a5bSBram Moolenaar * When "flags" has DIP_OPT: search also from 'opt' of 'packpath':
803307c5a5bSBram Moolenaar * 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim
804307c5a5bSBram Moolenaar * "dirnames" is an array with one or more directory names.
805307c5a5bSBram Moolenaar */
806307c5a5bSBram Moolenaar int
ExpandRTDir(char_u * pat,int flags,int * num_file,char_u *** file,char * dirnames[])807307c5a5bSBram Moolenaar ExpandRTDir(
808307c5a5bSBram Moolenaar char_u *pat,
809307c5a5bSBram Moolenaar int flags,
810307c5a5bSBram Moolenaar int *num_file,
811307c5a5bSBram Moolenaar char_u ***file,
812307c5a5bSBram Moolenaar char *dirnames[])
813307c5a5bSBram Moolenaar {
814307c5a5bSBram Moolenaar char_u *s;
815307c5a5bSBram Moolenaar char_u *e;
816307c5a5bSBram Moolenaar char_u *match;
817307c5a5bSBram Moolenaar garray_T ga;
818307c5a5bSBram Moolenaar int i;
819307c5a5bSBram Moolenaar int pat_len;
820307c5a5bSBram Moolenaar
821307c5a5bSBram Moolenaar *num_file = 0;
822307c5a5bSBram Moolenaar *file = NULL;
823307c5a5bSBram Moolenaar pat_len = (int)STRLEN(pat);
824307c5a5bSBram Moolenaar ga_init2(&ga, (int)sizeof(char *), 10);
825307c5a5bSBram Moolenaar
826307c5a5bSBram Moolenaar for (i = 0; dirnames[i] != NULL; ++i)
827307c5a5bSBram Moolenaar {
828307c5a5bSBram Moolenaar s = alloc(STRLEN(dirnames[i]) + pat_len + 7);
829307c5a5bSBram Moolenaar if (s == NULL)
830307c5a5bSBram Moolenaar {
831307c5a5bSBram Moolenaar ga_clear_strings(&ga);
832307c5a5bSBram Moolenaar return FAIL;
833307c5a5bSBram Moolenaar }
834307c5a5bSBram Moolenaar sprintf((char *)s, "%s/%s*.vim", dirnames[i], pat);
835307c5a5bSBram Moolenaar globpath(p_rtp, s, &ga, 0);
836307c5a5bSBram Moolenaar vim_free(s);
837307c5a5bSBram Moolenaar }
838307c5a5bSBram Moolenaar
839307c5a5bSBram Moolenaar if (flags & DIP_START) {
840307c5a5bSBram Moolenaar for (i = 0; dirnames[i] != NULL; ++i)
841307c5a5bSBram Moolenaar {
842307c5a5bSBram Moolenaar s = alloc(STRLEN(dirnames[i]) + pat_len + 22);
843307c5a5bSBram Moolenaar if (s == NULL)
844307c5a5bSBram Moolenaar {
845307c5a5bSBram Moolenaar ga_clear_strings(&ga);
846307c5a5bSBram Moolenaar return FAIL;
847307c5a5bSBram Moolenaar }
848307c5a5bSBram Moolenaar sprintf((char *)s, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat);
849307c5a5bSBram Moolenaar globpath(p_pp, s, &ga, 0);
850307c5a5bSBram Moolenaar vim_free(s);
851307c5a5bSBram Moolenaar }
852307c5a5bSBram Moolenaar }
853307c5a5bSBram Moolenaar
854307c5a5bSBram Moolenaar if (flags & DIP_OPT) {
855307c5a5bSBram Moolenaar for (i = 0; dirnames[i] != NULL; ++i)
856307c5a5bSBram Moolenaar {
857307c5a5bSBram Moolenaar s = alloc(STRLEN(dirnames[i]) + pat_len + 20);
858307c5a5bSBram Moolenaar if (s == NULL)
859307c5a5bSBram Moolenaar {
860307c5a5bSBram Moolenaar ga_clear_strings(&ga);
861307c5a5bSBram Moolenaar return FAIL;
862307c5a5bSBram Moolenaar }
863307c5a5bSBram Moolenaar sprintf((char *)s, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat);
864307c5a5bSBram Moolenaar globpath(p_pp, s, &ga, 0);
865307c5a5bSBram Moolenaar vim_free(s);
866307c5a5bSBram Moolenaar }
867307c5a5bSBram Moolenaar }
868307c5a5bSBram Moolenaar
869307c5a5bSBram Moolenaar for (i = 0; i < ga.ga_len; ++i)
870307c5a5bSBram Moolenaar {
871307c5a5bSBram Moolenaar match = ((char_u **)ga.ga_data)[i];
872307c5a5bSBram Moolenaar s = match;
873307c5a5bSBram Moolenaar e = s + STRLEN(s);
874307c5a5bSBram Moolenaar if (e - 4 > s && STRNICMP(e - 4, ".vim", 4) == 0)
875307c5a5bSBram Moolenaar {
876307c5a5bSBram Moolenaar e -= 4;
877307c5a5bSBram Moolenaar for (s = e; s > match; MB_PTR_BACK(match, s))
878307c5a5bSBram Moolenaar if (s < match || vim_ispathsep(*s))
879307c5a5bSBram Moolenaar break;
880307c5a5bSBram Moolenaar ++s;
881307c5a5bSBram Moolenaar *e = NUL;
882307c5a5bSBram Moolenaar mch_memmove(match, s, e - s + 1);
883307c5a5bSBram Moolenaar }
884307c5a5bSBram Moolenaar }
885307c5a5bSBram Moolenaar
886307c5a5bSBram Moolenaar if (ga.ga_len == 0)
887307c5a5bSBram Moolenaar return FAIL;
888307c5a5bSBram Moolenaar
889307c5a5bSBram Moolenaar // Sort and remove duplicates which can happen when specifying multiple
890307c5a5bSBram Moolenaar // directories in dirnames.
891307c5a5bSBram Moolenaar remove_duplicates(&ga);
892307c5a5bSBram Moolenaar
893307c5a5bSBram Moolenaar *file = ga.ga_data;
894307c5a5bSBram Moolenaar *num_file = ga.ga_len;
895307c5a5bSBram Moolenaar return OK;
896307c5a5bSBram Moolenaar }
897307c5a5bSBram Moolenaar
898307c5a5bSBram Moolenaar /*
899307c5a5bSBram Moolenaar * Expand loadplugin names:
900307c5a5bSBram Moolenaar * 'packpath'/pack/ * /opt/{pat}
901307c5a5bSBram Moolenaar */
902307c5a5bSBram Moolenaar int
ExpandPackAddDir(char_u * pat,int * num_file,char_u *** file)903307c5a5bSBram Moolenaar ExpandPackAddDir(
904307c5a5bSBram Moolenaar char_u *pat,
905307c5a5bSBram Moolenaar int *num_file,
906307c5a5bSBram Moolenaar char_u ***file)
907307c5a5bSBram Moolenaar {
908307c5a5bSBram Moolenaar char_u *s;
909307c5a5bSBram Moolenaar char_u *e;
910307c5a5bSBram Moolenaar char_u *match;
911307c5a5bSBram Moolenaar garray_T ga;
912307c5a5bSBram Moolenaar int i;
913307c5a5bSBram Moolenaar int pat_len;
914307c5a5bSBram Moolenaar
915307c5a5bSBram Moolenaar *num_file = 0;
916307c5a5bSBram Moolenaar *file = NULL;
917307c5a5bSBram Moolenaar pat_len = (int)STRLEN(pat);
918307c5a5bSBram Moolenaar ga_init2(&ga, (int)sizeof(char *), 10);
919307c5a5bSBram Moolenaar
920307c5a5bSBram Moolenaar s = alloc(pat_len + 26);
921307c5a5bSBram Moolenaar if (s == NULL)
922307c5a5bSBram Moolenaar {
923307c5a5bSBram Moolenaar ga_clear_strings(&ga);
924307c5a5bSBram Moolenaar return FAIL;
925307c5a5bSBram Moolenaar }
926307c5a5bSBram Moolenaar sprintf((char *)s, "pack/*/opt/%s*", pat);
927307c5a5bSBram Moolenaar globpath(p_pp, s, &ga, 0);
928307c5a5bSBram Moolenaar vim_free(s);
929307c5a5bSBram Moolenaar
930307c5a5bSBram Moolenaar for (i = 0; i < ga.ga_len; ++i)
931307c5a5bSBram Moolenaar {
932307c5a5bSBram Moolenaar match = ((char_u **)ga.ga_data)[i];
933307c5a5bSBram Moolenaar s = gettail(match);
934307c5a5bSBram Moolenaar e = s + STRLEN(s);
935307c5a5bSBram Moolenaar mch_memmove(match, s, e - s + 1);
936307c5a5bSBram Moolenaar }
937307c5a5bSBram Moolenaar
938307c5a5bSBram Moolenaar if (ga.ga_len == 0)
939307c5a5bSBram Moolenaar return FAIL;
940307c5a5bSBram Moolenaar
941307c5a5bSBram Moolenaar // Sort and remove duplicates which can happen when specifying multiple
942307c5a5bSBram Moolenaar // directories in dirnames.
943307c5a5bSBram Moolenaar remove_duplicates(&ga);
944307c5a5bSBram Moolenaar
945307c5a5bSBram Moolenaar *file = ga.ga_data;
946307c5a5bSBram Moolenaar *num_file = ga.ga_len;
947307c5a5bSBram Moolenaar return OK;
948307c5a5bSBram Moolenaar }
949307c5a5bSBram Moolenaar
950307c5a5bSBram Moolenaar static void
cmd_source(char_u * fname,exarg_T * eap)951307c5a5bSBram Moolenaar cmd_source(char_u *fname, exarg_T *eap)
952307c5a5bSBram Moolenaar {
953307c5a5bSBram Moolenaar if (*fname == NUL)
954307c5a5bSBram Moolenaar emsg(_(e_argreq));
955307c5a5bSBram Moolenaar
956307c5a5bSBram Moolenaar else if (eap != NULL && eap->forceit)
957307c5a5bSBram Moolenaar // ":source!": read Normal mode commands
958307c5a5bSBram Moolenaar // Need to execute the commands directly. This is required at least
959307c5a5bSBram Moolenaar // for:
960307c5a5bSBram Moolenaar // - ":g" command busy
961307c5a5bSBram Moolenaar // - after ":argdo", ":windo" or ":bufdo"
962307c5a5bSBram Moolenaar // - another command follows
963307c5a5bSBram Moolenaar // - inside a loop
964307c5a5bSBram Moolenaar openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
965307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
966307c5a5bSBram Moolenaar || eap->cstack->cs_idx >= 0
967307c5a5bSBram Moolenaar #endif
968307c5a5bSBram Moolenaar );
969307c5a5bSBram Moolenaar
970307c5a5bSBram Moolenaar // ":source" read ex commands
9718a7d6542SBram Moolenaar else if (do_source(fname, FALSE, DOSO_NONE, NULL) == FAIL)
972307c5a5bSBram Moolenaar semsg(_(e_notopen), fname);
973307c5a5bSBram Moolenaar }
974307c5a5bSBram Moolenaar
975307c5a5bSBram Moolenaar /*
976307c5a5bSBram Moolenaar * ":source {fname}"
977307c5a5bSBram Moolenaar */
978307c5a5bSBram Moolenaar void
ex_source(exarg_T * eap)979307c5a5bSBram Moolenaar ex_source(exarg_T *eap)
980307c5a5bSBram Moolenaar {
981307c5a5bSBram Moolenaar #ifdef FEAT_BROWSE
982e1004401SBram Moolenaar if (cmdmod.cmod_flags & CMOD_BROWSE)
983307c5a5bSBram Moolenaar {
984307c5a5bSBram Moolenaar char_u *fname = NULL;
985307c5a5bSBram Moolenaar
986307c5a5bSBram Moolenaar fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
987307c5a5bSBram Moolenaar NULL, NULL,
988307c5a5bSBram Moolenaar (char_u *)_(BROWSE_FILTER_MACROS), NULL);
989307c5a5bSBram Moolenaar if (fname != NULL)
990307c5a5bSBram Moolenaar {
991307c5a5bSBram Moolenaar cmd_source(fname, eap);
992307c5a5bSBram Moolenaar vim_free(fname);
993307c5a5bSBram Moolenaar }
994307c5a5bSBram Moolenaar }
995307c5a5bSBram Moolenaar else
996307c5a5bSBram Moolenaar #endif
997307c5a5bSBram Moolenaar cmd_source(eap->arg, eap);
998307c5a5bSBram Moolenaar }
999307c5a5bSBram Moolenaar
1000307c5a5bSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
1001307c5a5bSBram Moolenaar /*
1002307c5a5bSBram Moolenaar * ":options"
1003307c5a5bSBram Moolenaar */
1004307c5a5bSBram Moolenaar void
ex_options(exarg_T * eap UNUSED)1005307c5a5bSBram Moolenaar ex_options(
1006307c5a5bSBram Moolenaar exarg_T *eap UNUSED)
1007307c5a5bSBram Moolenaar {
10087a1637f4SBram Moolenaar char_u buf[500];
10097a1637f4SBram Moolenaar int multi_mods = 0;
10107a1637f4SBram Moolenaar
10117a1637f4SBram Moolenaar buf[0] = NUL;
101202194d2bSBram Moolenaar (void)add_win_cmd_modifers(buf, &cmdmod, &multi_mods);
10137a1637f4SBram Moolenaar
10147a1637f4SBram Moolenaar vim_setenv((char_u *)"OPTWIN_CMD", buf);
1015307c5a5bSBram Moolenaar cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
1016307c5a5bSBram Moolenaar }
1017307c5a5bSBram Moolenaar #endif
1018307c5a5bSBram Moolenaar
1019307c5a5bSBram Moolenaar /*
1020307c5a5bSBram Moolenaar * ":source" and associated commands.
1021307c5a5bSBram Moolenaar */
1022307c5a5bSBram Moolenaar
1023307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1024307c5a5bSBram Moolenaar /*
1025307c5a5bSBram Moolenaar * Return the address holding the next breakpoint line for a source cookie.
1026307c5a5bSBram Moolenaar */
1027307c5a5bSBram Moolenaar linenr_T *
source_breakpoint(void * cookie)1028307c5a5bSBram Moolenaar source_breakpoint(void *cookie)
1029307c5a5bSBram Moolenaar {
10309567efa1SBram Moolenaar return &((source_cookie_T *)cookie)->breakpoint;
1031307c5a5bSBram Moolenaar }
1032307c5a5bSBram Moolenaar
1033307c5a5bSBram Moolenaar /*
1034307c5a5bSBram Moolenaar * Return the address holding the debug tick for a source cookie.
1035307c5a5bSBram Moolenaar */
1036307c5a5bSBram Moolenaar int *
source_dbg_tick(void * cookie)1037307c5a5bSBram Moolenaar source_dbg_tick(void *cookie)
1038307c5a5bSBram Moolenaar {
10399567efa1SBram Moolenaar return &((source_cookie_T *)cookie)->dbg_tick;
1040307c5a5bSBram Moolenaar }
1041307c5a5bSBram Moolenaar
1042307c5a5bSBram Moolenaar /*
1043307c5a5bSBram Moolenaar * Return the nesting level for a source cookie.
1044307c5a5bSBram Moolenaar */
1045307c5a5bSBram Moolenaar int
source_level(void * cookie)1046307c5a5bSBram Moolenaar source_level(void *cookie)
1047307c5a5bSBram Moolenaar {
10489567efa1SBram Moolenaar return ((source_cookie_T *)cookie)->level;
1049307c5a5bSBram Moolenaar }
10505409f5d8SBram Moolenaar
10515409f5d8SBram Moolenaar /*
1052aeb2bdd0SBram Moolenaar * Return the readahead line. Note that the pointer may become invalid when
1053aeb2bdd0SBram Moolenaar * getting the next line, if it's concatenated with the next one.
10545409f5d8SBram Moolenaar */
10555409f5d8SBram Moolenaar char_u *
source_nextline(void * cookie)10565409f5d8SBram Moolenaar source_nextline(void *cookie)
10575409f5d8SBram Moolenaar {
10589567efa1SBram Moolenaar return ((source_cookie_T *)cookie)->nextline;
10595409f5d8SBram Moolenaar }
1060307c5a5bSBram Moolenaar #endif
1061307c5a5bSBram Moolenaar
1062307c5a5bSBram Moolenaar #if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
1063307c5a5bSBram Moolenaar # define USE_FOPEN_NOINH
1064307c5a5bSBram Moolenaar /*
1065307c5a5bSBram Moolenaar * Special function to open a file without handle inheritance.
1066307c5a5bSBram Moolenaar * When possible the handle is closed on exec().
1067307c5a5bSBram Moolenaar */
1068307c5a5bSBram Moolenaar static FILE *
fopen_noinh_readbin(char * filename)1069307c5a5bSBram Moolenaar fopen_noinh_readbin(char *filename)
1070307c5a5bSBram Moolenaar {
1071307c5a5bSBram Moolenaar # ifdef MSWIN
1072307c5a5bSBram Moolenaar int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
1073307c5a5bSBram Moolenaar # else
1074307c5a5bSBram Moolenaar int fd_tmp = mch_open(filename, O_RDONLY, 0);
1075307c5a5bSBram Moolenaar # endif
1076307c5a5bSBram Moolenaar
1077307c5a5bSBram Moolenaar if (fd_tmp == -1)
1078307c5a5bSBram Moolenaar return NULL;
1079307c5a5bSBram Moolenaar
1080307c5a5bSBram Moolenaar # ifdef HAVE_FD_CLOEXEC
1081307c5a5bSBram Moolenaar {
1082307c5a5bSBram Moolenaar int fdflags = fcntl(fd_tmp, F_GETFD);
1083307c5a5bSBram Moolenaar if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
1084307c5a5bSBram Moolenaar (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
1085307c5a5bSBram Moolenaar }
1086307c5a5bSBram Moolenaar # endif
1087307c5a5bSBram Moolenaar
1088307c5a5bSBram Moolenaar return fdopen(fd_tmp, READBIN);
1089307c5a5bSBram Moolenaar }
1090307c5a5bSBram Moolenaar #endif
1091307c5a5bSBram Moolenaar
1092307c5a5bSBram Moolenaar /*
1093307c5a5bSBram Moolenaar * do_source: Read the file "fname" and execute its lines as EX commands.
10948a7d6542SBram Moolenaar * When "ret_sid" is not NULL and we loaded the script before, don't load it
10958a7d6542SBram Moolenaar * again.
1096307c5a5bSBram Moolenaar *
1097307c5a5bSBram Moolenaar * This function may be called recursively!
1098307c5a5bSBram Moolenaar *
10998a7d6542SBram Moolenaar * Return FAIL if file could not be opened, OK otherwise.
11008a7d6542SBram Moolenaar * If a scriptitem_T was found or created "*ret_sid" is set to the SID.
1101307c5a5bSBram Moolenaar */
1102307c5a5bSBram Moolenaar int
do_source(char_u * fname,int check_other,int is_vimrc,int * ret_sid UNUSED)1103307c5a5bSBram Moolenaar do_source(
1104307c5a5bSBram Moolenaar char_u *fname,
1105307c5a5bSBram Moolenaar int check_other, // check for .vimrc and _vimrc
11068a7d6542SBram Moolenaar int is_vimrc, // DOSO_ value
11078a7d6542SBram Moolenaar int *ret_sid UNUSED)
1108307c5a5bSBram Moolenaar {
11099567efa1SBram Moolenaar source_cookie_T cookie;
1110307c5a5bSBram Moolenaar char_u *p;
1111307c5a5bSBram Moolenaar char_u *fname_exp;
1112307c5a5bSBram Moolenaar char_u *firstline = NULL;
1113307c5a5bSBram Moolenaar int retval = FAIL;
1114307c5a5bSBram Moolenaar sctx_T save_current_sctx;
11159b8d6226SBram Moolenaar #ifdef FEAT_EVAL
1116307c5a5bSBram Moolenaar static scid_T last_current_SID = 0;
1117307c5a5bSBram Moolenaar static int last_current_SID_seq = 0;
1118307c5a5bSBram Moolenaar funccal_entry_T funccalp_entry;
1119307c5a5bSBram Moolenaar int save_debug_break_level = debug_break_level;
11208a7d6542SBram Moolenaar int sid;
1121307c5a5bSBram Moolenaar scriptitem_T *si = NULL;
1122*8de901e1SBram Moolenaar int save_estack_compiling = estack_compiling;
1123307c5a5bSBram Moolenaar #endif
1124307c5a5bSBram Moolenaar #ifdef STARTUPTIME
1125307c5a5bSBram Moolenaar struct timeval tv_rel;
1126307c5a5bSBram Moolenaar struct timeval tv_start;
1127307c5a5bSBram Moolenaar #endif
1128307c5a5bSBram Moolenaar #ifdef FEAT_PROFILE
1129307c5a5bSBram Moolenaar proftime_T wait_start;
1130307c5a5bSBram Moolenaar #endif
1131307c5a5bSBram Moolenaar int trigger_source_post = FALSE;
1132e31ee868SBram Moolenaar ESTACK_CHECK_DECLARATION
1133307c5a5bSBram Moolenaar
1134307c5a5bSBram Moolenaar p = expand_env_save(fname);
1135307c5a5bSBram Moolenaar if (p == NULL)
1136307c5a5bSBram Moolenaar return retval;
1137307c5a5bSBram Moolenaar fname_exp = fix_fname(p);
1138307c5a5bSBram Moolenaar vim_free(p);
1139307c5a5bSBram Moolenaar if (fname_exp == NULL)
1140307c5a5bSBram Moolenaar return retval;
1141307c5a5bSBram Moolenaar if (mch_isdir(fname_exp))
1142307c5a5bSBram Moolenaar {
1143307c5a5bSBram Moolenaar smsg(_("Cannot source a directory: \"%s\""), fname);
1144307c5a5bSBram Moolenaar goto theend;
1145307c5a5bSBram Moolenaar }
1146*8de901e1SBram Moolenaar #ifdef FEAT_EVAL
1147f0a4069eSBram Moolenaar estack_compiling = FALSE;
1148307c5a5bSBram Moolenaar
11498a7d6542SBram Moolenaar // See if we loaded this script before.
11508a7d6542SBram Moolenaar for (sid = script_items.ga_len; sid > 0; --sid)
11518a7d6542SBram Moolenaar {
1152978d170bSBram Moolenaar // We used to check inode here, but that doesn't work:
1153978d170bSBram Moolenaar // - If a script is edited and written, it may get a different
1154978d170bSBram Moolenaar // inode number, even though to the user it is the same script.
1155978d170bSBram Moolenaar // - If a script is deleted and another script is written, with a
1156978d170bSBram Moolenaar // different name, the inode may be re-used.
115721b9e977SBram Moolenaar si = SCRIPT_ITEM(sid);
1158978d170bSBram Moolenaar if (si->sn_name != NULL && fnamecmp(si->sn_name, fname_exp) == 0)
11598a7d6542SBram Moolenaar // Found it!
11608a7d6542SBram Moolenaar break;
11618a7d6542SBram Moolenaar }
11628a7d6542SBram Moolenaar if (sid > 0 && ret_sid != NULL)
11638a7d6542SBram Moolenaar {
11648a7d6542SBram Moolenaar // Already loaded and no need to load again, return here.
11658a7d6542SBram Moolenaar *ret_sid = sid;
1166292b90d4SBram Moolenaar retval = OK;
1167292b90d4SBram Moolenaar goto theend;
11688a7d6542SBram Moolenaar }
11698a7d6542SBram Moolenaar #endif
11708a7d6542SBram Moolenaar
1171307c5a5bSBram Moolenaar // Apply SourceCmd autocommands, they should get the file and source it.
1172307c5a5bSBram Moolenaar if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
1173307c5a5bSBram Moolenaar && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
1174307c5a5bSBram Moolenaar FALSE, curbuf))
1175307c5a5bSBram Moolenaar {
1176307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1177307c5a5bSBram Moolenaar retval = aborting() ? FAIL : OK;
1178307c5a5bSBram Moolenaar #else
1179307c5a5bSBram Moolenaar retval = OK;
1180307c5a5bSBram Moolenaar #endif
1181307c5a5bSBram Moolenaar if (retval == OK)
1182307c5a5bSBram Moolenaar // Apply SourcePost autocommands.
1183307c5a5bSBram Moolenaar apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp,
1184307c5a5bSBram Moolenaar FALSE, curbuf);
1185307c5a5bSBram Moolenaar goto theend;
1186307c5a5bSBram Moolenaar }
1187307c5a5bSBram Moolenaar
1188307c5a5bSBram Moolenaar // Apply SourcePre autocommands, they may get the file.
1189307c5a5bSBram Moolenaar apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
1190307c5a5bSBram Moolenaar
1191307c5a5bSBram Moolenaar #ifdef USE_FOPEN_NOINH
1192307c5a5bSBram Moolenaar cookie.fp = fopen_noinh_readbin((char *)fname_exp);
1193307c5a5bSBram Moolenaar #else
1194307c5a5bSBram Moolenaar cookie.fp = mch_fopen((char *)fname_exp, READBIN);
1195307c5a5bSBram Moolenaar #endif
1196307c5a5bSBram Moolenaar if (cookie.fp == NULL && check_other)
1197307c5a5bSBram Moolenaar {
1198307c5a5bSBram Moolenaar // Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
1199307c5a5bSBram Moolenaar // and ".exrc" by "_exrc" or vice versa.
1200307c5a5bSBram Moolenaar p = gettail(fname_exp);
1201307c5a5bSBram Moolenaar if ((*p == '.' || *p == '_')
1202307c5a5bSBram Moolenaar && (STRICMP(p + 1, "vimrc") == 0
1203307c5a5bSBram Moolenaar || STRICMP(p + 1, "gvimrc") == 0
1204307c5a5bSBram Moolenaar || STRICMP(p + 1, "exrc") == 0))
1205307c5a5bSBram Moolenaar {
1206307c5a5bSBram Moolenaar if (*p == '_')
1207307c5a5bSBram Moolenaar *p = '.';
1208307c5a5bSBram Moolenaar else
1209307c5a5bSBram Moolenaar *p = '_';
1210307c5a5bSBram Moolenaar #ifdef USE_FOPEN_NOINH
1211307c5a5bSBram Moolenaar cookie.fp = fopen_noinh_readbin((char *)fname_exp);
1212307c5a5bSBram Moolenaar #else
1213307c5a5bSBram Moolenaar cookie.fp = mch_fopen((char *)fname_exp, READBIN);
1214307c5a5bSBram Moolenaar #endif
1215307c5a5bSBram Moolenaar }
1216307c5a5bSBram Moolenaar }
1217307c5a5bSBram Moolenaar
1218307c5a5bSBram Moolenaar if (cookie.fp == NULL)
1219307c5a5bSBram Moolenaar {
1220307c5a5bSBram Moolenaar if (p_verbose > 0)
1221307c5a5bSBram Moolenaar {
1222307c5a5bSBram Moolenaar verbose_enter();
12231a47ae32SBram Moolenaar if (SOURCING_NAME == NULL)
1224307c5a5bSBram Moolenaar smsg(_("could not source \"%s\""), fname);
1225307c5a5bSBram Moolenaar else
1226307c5a5bSBram Moolenaar smsg(_("line %ld: could not source \"%s\""),
12271a47ae32SBram Moolenaar SOURCING_LNUM, fname);
1228307c5a5bSBram Moolenaar verbose_leave();
1229307c5a5bSBram Moolenaar }
1230307c5a5bSBram Moolenaar goto theend;
1231307c5a5bSBram Moolenaar }
1232307c5a5bSBram Moolenaar
1233307c5a5bSBram Moolenaar // The file exists.
1234307c5a5bSBram Moolenaar // - In verbose mode, give a message.
1235307c5a5bSBram Moolenaar // - For a vimrc file, may want to set 'compatible', call vimrc_found().
1236307c5a5bSBram Moolenaar if (p_verbose > 1)
1237307c5a5bSBram Moolenaar {
1238307c5a5bSBram Moolenaar verbose_enter();
12391a47ae32SBram Moolenaar if (SOURCING_NAME == NULL)
1240307c5a5bSBram Moolenaar smsg(_("sourcing \"%s\""), fname);
1241307c5a5bSBram Moolenaar else
12421a47ae32SBram Moolenaar smsg(_("line %ld: sourcing \"%s\""), SOURCING_LNUM, fname);
1243307c5a5bSBram Moolenaar verbose_leave();
1244307c5a5bSBram Moolenaar }
1245307c5a5bSBram Moolenaar if (is_vimrc == DOSO_VIMRC)
1246307c5a5bSBram Moolenaar vimrc_found(fname_exp, (char_u *)"MYVIMRC");
1247307c5a5bSBram Moolenaar else if (is_vimrc == DOSO_GVIMRC)
1248307c5a5bSBram Moolenaar vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
1249307c5a5bSBram Moolenaar
1250307c5a5bSBram Moolenaar #ifdef USE_CRNL
1251307c5a5bSBram Moolenaar // If no automatic file format: Set default to CR-NL.
1252307c5a5bSBram Moolenaar if (*p_ffs == NUL)
1253307c5a5bSBram Moolenaar cookie.fileformat = EOL_DOS;
1254307c5a5bSBram Moolenaar else
1255307c5a5bSBram Moolenaar cookie.fileformat = EOL_UNKNOWN;
1256307c5a5bSBram Moolenaar cookie.error = FALSE;
1257307c5a5bSBram Moolenaar #endif
1258307c5a5bSBram Moolenaar
1259307c5a5bSBram Moolenaar cookie.nextline = NULL;
1260307c5a5bSBram Moolenaar cookie.sourcing_lnum = 0;
1261307c5a5bSBram Moolenaar cookie.finished = FALSE;
1262307c5a5bSBram Moolenaar
1263307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1264307c5a5bSBram Moolenaar // Check if this script has a breakpoint.
1265307c5a5bSBram Moolenaar cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
1266307c5a5bSBram Moolenaar cookie.fname = fname_exp;
1267307c5a5bSBram Moolenaar cookie.dbg_tick = debug_tick;
1268307c5a5bSBram Moolenaar
1269307c5a5bSBram Moolenaar cookie.level = ex_nesting_level;
1270307c5a5bSBram Moolenaar #endif
1271307c5a5bSBram Moolenaar
1272307c5a5bSBram Moolenaar // Keep the sourcing name/lnum, for recursive calls.
12731a47ae32SBram Moolenaar estack_push(ETYPE_SCRIPT, fname_exp, 0);
1274e31ee868SBram Moolenaar ESTACK_CHECK_SETUP
1275307c5a5bSBram Moolenaar
1276307c5a5bSBram Moolenaar #ifdef STARTUPTIME
1277307c5a5bSBram Moolenaar if (time_fd != NULL)
1278307c5a5bSBram Moolenaar time_push(&tv_rel, &tv_start);
1279307c5a5bSBram Moolenaar #endif
1280307c5a5bSBram Moolenaar
12819b8d6226SBram Moolenaar save_current_sctx = current_sctx;
12829b8d6226SBram Moolenaar current_sctx.sc_version = 1; // default script version
12839b8d6226SBram Moolenaar
1284307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1285307c5a5bSBram Moolenaar # ifdef FEAT_PROFILE
1286307c5a5bSBram Moolenaar if (do_profiling == PROF_YES)
1287307c5a5bSBram Moolenaar prof_child_enter(&wait_start); // entering a child now
1288307c5a5bSBram Moolenaar # endif
1289307c5a5bSBram Moolenaar
1290307c5a5bSBram Moolenaar // Don't use local function variables, if called from a function.
1291307c5a5bSBram Moolenaar // Also starts profiling timer for nested script.
1292307c5a5bSBram Moolenaar save_funccal(&funccalp_entry);
1293307c5a5bSBram Moolenaar
1294307c5a5bSBram Moolenaar current_sctx.sc_lnum = 0;
1295307c5a5bSBram Moolenaar
1296307c5a5bSBram Moolenaar // Check if this script was sourced before to finds its SID.
1297307c5a5bSBram Moolenaar // Always use a new sequence number.
1298307c5a5bSBram Moolenaar current_sctx.sc_seq = ++last_current_SID_seq;
12998a7d6542SBram Moolenaar if (sid > 0)
1300307c5a5bSBram Moolenaar {
13018a7d6542SBram Moolenaar hashtab_T *ht;
13022b32700dSBram Moolenaar int todo;
130389483d40SBram Moolenaar hashitem_T *hi;
130489483d40SBram Moolenaar dictitem_T *di;
130589483d40SBram Moolenaar
13062b32700dSBram Moolenaar // loading the same script again
13072b32700dSBram Moolenaar si->sn_state = SN_STATE_RELOAD;
13082b32700dSBram Moolenaar current_sctx.sc_sid = sid;
13092b32700dSBram Moolenaar
13102b32700dSBram Moolenaar // Script-local variables remain but "const" can be set again.
13112b32700dSBram Moolenaar // In Vim9 script variables will be cleared when "vim9script" is
13122b32700dSBram Moolenaar // encountered without the "noclear" argument.
13132b32700dSBram Moolenaar ht = &SCRIPT_VARS(sid);
13142b32700dSBram Moolenaar todo = (int)ht->ht_used;
13158a7d6542SBram Moolenaar for (hi = ht->ht_array; todo > 0; ++hi)
13168a7d6542SBram Moolenaar if (!HASHITEM_EMPTY(hi))
1317ca33eb25SBram Moolenaar {
13188a7d6542SBram Moolenaar --todo;
13198a7d6542SBram Moolenaar di = HI2DI(hi);
13208a7d6542SBram Moolenaar di->di_flags |= DI_FLAGS_RELOAD;
1321307c5a5bSBram Moolenaar }
13227e3ee782SBram Moolenaar // imports can be redefined once
13237e3ee782SBram Moolenaar mark_imports_for_reload(sid);
13240123cc1eSBram Moolenaar
13250123cc1eSBram Moolenaar // reset version, "vim9script" may have been added or removed.
13260123cc1eSBram Moolenaar si->sn_version = 1;
132789483d40SBram Moolenaar }
13288a7d6542SBram Moolenaar else
1329307c5a5bSBram Moolenaar {
13308a7d6542SBram Moolenaar // It's new, generate a new SID.
1331307c5a5bSBram Moolenaar current_sctx.sc_sid = ++last_current_SID;
1332307c5a5bSBram Moolenaar if (ga_grow(&script_items,
1333307c5a5bSBram Moolenaar (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
1334307c5a5bSBram Moolenaar goto almosttheend;
1335307c5a5bSBram Moolenaar while (script_items.ga_len < current_sctx.sc_sid)
1336307c5a5bSBram Moolenaar {
133721b9e977SBram Moolenaar si = ALLOC_CLEAR_ONE(scriptitem_T);
133821b9e977SBram Moolenaar if (si == NULL)
133921b9e977SBram Moolenaar goto almosttheend;
1340307c5a5bSBram Moolenaar ++script_items.ga_len;
134121b9e977SBram Moolenaar SCRIPT_ITEM(script_items.ga_len) = si;
13428a7d6542SBram Moolenaar si->sn_name = NULL;
13438a7d6542SBram Moolenaar si->sn_version = 1;
13447ebcba61SBram Moolenaar
13457ebcba61SBram Moolenaar // Allocate the local script variables to use for this script.
13467ebcba61SBram Moolenaar new_script_vars(script_items.ga_len);
13473b74b6b4SBram Moolenaar ga_init2(&si->sn_var_vals, sizeof(svar_T), 10);
13488d739de4SBram Moolenaar hash_init(&si->sn_all_vars.dv_hashtab);
13498a7d6542SBram Moolenaar ga_init2(&si->sn_imports, sizeof(imported_T), 10);
13508a7d6542SBram Moolenaar ga_init2(&si->sn_type_list, sizeof(type_T), 10);
1351307c5a5bSBram Moolenaar # ifdef FEAT_PROFILE
13528a7d6542SBram Moolenaar si->sn_prof_on = FALSE;
1353307c5a5bSBram Moolenaar # endif
1354307c5a5bSBram Moolenaar }
135521b9e977SBram Moolenaar si = SCRIPT_ITEM(current_sctx.sc_sid);
1356307c5a5bSBram Moolenaar si->sn_name = fname_exp;
1357307c5a5bSBram Moolenaar fname_exp = vim_strsave(si->sn_name); // used for autocmd
13588a7d6542SBram Moolenaar if (ret_sid != NULL)
13598a7d6542SBram Moolenaar *ret_sid = current_sctx.sc_sid;
13602b32700dSBram Moolenaar
13612b32700dSBram Moolenaar // Used to check script variable index is still valid.
13624aab88d9SBram Moolenaar si->sn_script_seq = current_sctx.sc_seq;
13632b32700dSBram Moolenaar }
1364307c5a5bSBram Moolenaar
1365307c5a5bSBram Moolenaar # ifdef FEAT_PROFILE
1366307c5a5bSBram Moolenaar if (do_profiling == PROF_YES)
1367307c5a5bSBram Moolenaar {
1368307c5a5bSBram Moolenaar int forceit;
1369307c5a5bSBram Moolenaar
1370307c5a5bSBram Moolenaar // Check if we do profiling for this script.
1371307c5a5bSBram Moolenaar if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
1372307c5a5bSBram Moolenaar {
1373307c5a5bSBram Moolenaar script_do_profile(si);
1374307c5a5bSBram Moolenaar si->sn_pr_force = forceit;
1375307c5a5bSBram Moolenaar }
1376307c5a5bSBram Moolenaar if (si->sn_prof_on)
1377307c5a5bSBram Moolenaar {
1378307c5a5bSBram Moolenaar ++si->sn_pr_count;
1379307c5a5bSBram Moolenaar profile_start(&si->sn_pr_start);
1380307c5a5bSBram Moolenaar profile_zero(&si->sn_pr_children);
1381307c5a5bSBram Moolenaar }
1382307c5a5bSBram Moolenaar }
1383307c5a5bSBram Moolenaar # endif
1384307c5a5bSBram Moolenaar #endif
1385307c5a5bSBram Moolenaar
1386307c5a5bSBram Moolenaar cookie.conv.vc_type = CONV_NONE; // no conversion
1387307c5a5bSBram Moolenaar
1388307c5a5bSBram Moolenaar // Read the first line so we can check for a UTF-8 BOM.
1389307c5a5bSBram Moolenaar firstline = getsourceline(0, (void *)&cookie, 0, TRUE);
1390307c5a5bSBram Moolenaar if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
1391307c5a5bSBram Moolenaar && firstline[1] == 0xbb && firstline[2] == 0xbf)
1392307c5a5bSBram Moolenaar {
1393307c5a5bSBram Moolenaar // Found BOM; setup conversion, skip over BOM and recode the line.
1394307c5a5bSBram Moolenaar convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
1395307c5a5bSBram Moolenaar p = string_convert(&cookie.conv, firstline + 3, NULL);
1396307c5a5bSBram Moolenaar if (p == NULL)
1397307c5a5bSBram Moolenaar p = vim_strsave(firstline + 3);
1398307c5a5bSBram Moolenaar if (p != NULL)
1399307c5a5bSBram Moolenaar {
1400307c5a5bSBram Moolenaar vim_free(firstline);
1401307c5a5bSBram Moolenaar firstline = p;
1402307c5a5bSBram Moolenaar }
1403307c5a5bSBram Moolenaar }
1404307c5a5bSBram Moolenaar
1405307c5a5bSBram Moolenaar // Call do_cmdline, which will call getsourceline() to get the lines.
1406307c5a5bSBram Moolenaar do_cmdline(firstline, getsourceline, (void *)&cookie,
1407307c5a5bSBram Moolenaar DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
1408307c5a5bSBram Moolenaar retval = OK;
1409307c5a5bSBram Moolenaar
1410307c5a5bSBram Moolenaar #ifdef FEAT_PROFILE
1411307c5a5bSBram Moolenaar if (do_profiling == PROF_YES)
1412307c5a5bSBram Moolenaar {
1413307c5a5bSBram Moolenaar // Get "si" again, "script_items" may have been reallocated.
141421b9e977SBram Moolenaar si = SCRIPT_ITEM(current_sctx.sc_sid);
1415307c5a5bSBram Moolenaar if (si->sn_prof_on)
1416307c5a5bSBram Moolenaar {
1417307c5a5bSBram Moolenaar profile_end(&si->sn_pr_start);
1418307c5a5bSBram Moolenaar profile_sub_wait(&wait_start, &si->sn_pr_start);
1419307c5a5bSBram Moolenaar profile_add(&si->sn_pr_total, &si->sn_pr_start);
1420307c5a5bSBram Moolenaar profile_self(&si->sn_pr_self, &si->sn_pr_start,
1421307c5a5bSBram Moolenaar &si->sn_pr_children);
1422307c5a5bSBram Moolenaar }
1423307c5a5bSBram Moolenaar }
1424307c5a5bSBram Moolenaar #endif
1425307c5a5bSBram Moolenaar
1426307c5a5bSBram Moolenaar if (got_int)
1427307c5a5bSBram Moolenaar emsg(_(e_interr));
1428e31ee868SBram Moolenaar ESTACK_CHECK_NOW
14291a47ae32SBram Moolenaar estack_pop();
1430307c5a5bSBram Moolenaar if (p_verbose > 1)
1431307c5a5bSBram Moolenaar {
1432307c5a5bSBram Moolenaar verbose_enter();
1433307c5a5bSBram Moolenaar smsg(_("finished sourcing %s"), fname);
14341a47ae32SBram Moolenaar if (SOURCING_NAME != NULL)
14351a47ae32SBram Moolenaar smsg(_("continuing in %s"), SOURCING_NAME);
1436307c5a5bSBram Moolenaar verbose_leave();
1437307c5a5bSBram Moolenaar }
1438307c5a5bSBram Moolenaar #ifdef STARTUPTIME
1439307c5a5bSBram Moolenaar if (time_fd != NULL)
1440307c5a5bSBram Moolenaar {
1441307c5a5bSBram Moolenaar vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
1442307c5a5bSBram Moolenaar time_msg((char *)IObuff, &tv_start);
1443307c5a5bSBram Moolenaar time_pop(&tv_rel);
1444307c5a5bSBram Moolenaar }
1445307c5a5bSBram Moolenaar #endif
1446307c5a5bSBram Moolenaar
1447307c5a5bSBram Moolenaar if (!got_int)
1448307c5a5bSBram Moolenaar trigger_source_post = TRUE;
1449307c5a5bSBram Moolenaar
1450307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1451307c5a5bSBram Moolenaar // After a "finish" in debug mode, need to break at first command of next
1452307c5a5bSBram Moolenaar // sourced file.
1453307c5a5bSBram Moolenaar if (save_debug_break_level > ex_nesting_level
1454307c5a5bSBram Moolenaar && debug_break_level == ex_nesting_level)
1455307c5a5bSBram Moolenaar ++debug_break_level;
1456307c5a5bSBram Moolenaar #endif
1457307c5a5bSBram Moolenaar
1458307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1459307c5a5bSBram Moolenaar almosttheend:
14608a7d6542SBram Moolenaar // Get "si" again, "script_items" may have been reallocated.
146121b9e977SBram Moolenaar si = SCRIPT_ITEM(current_sctx.sc_sid);
14628a7d6542SBram Moolenaar if (si->sn_save_cpo != NULL)
14638a7d6542SBram Moolenaar {
14643e191694SBram Moolenaar if (STRCMP(p_cpo, CPO_VIM) != 0)
14653e191694SBram Moolenaar {
14663e191694SBram Moolenaar char_u *f;
14673e191694SBram Moolenaar char_u *t;
14683e191694SBram Moolenaar
14693e191694SBram Moolenaar // 'cpo' was changed in the script. Apply the same change to the
14703e191694SBram Moolenaar // saved value, if possible.
14713e191694SBram Moolenaar for (f = (char_u *)CPO_VIM; *f != NUL; ++f)
14723e191694SBram Moolenaar if (vim_strchr(p_cpo, *f) == NULL
14733e191694SBram Moolenaar && (t = vim_strchr(si->sn_save_cpo, *f)) != NULL)
14743e191694SBram Moolenaar // flag was removed, also remove it from the saved 'cpo'
14753e191694SBram Moolenaar mch_memmove(t, t + 1, STRLEN(t));
14763e191694SBram Moolenaar for (f = p_cpo; *f != NUL; ++f)
14773e191694SBram Moolenaar if (vim_strchr((char_u *)CPO_VIM, *f) == NULL
14783e191694SBram Moolenaar && vim_strchr(si->sn_save_cpo, *f) == NULL)
14793e191694SBram Moolenaar {
14803e191694SBram Moolenaar // flag was added, also add it to the saved 'cpo'
14813e191694SBram Moolenaar t = alloc(STRLEN(si->sn_save_cpo) + 2);
14823e191694SBram Moolenaar if (t != NULL)
14833e191694SBram Moolenaar {
14843e191694SBram Moolenaar *t = *f;
14853e191694SBram Moolenaar STRCPY(t + 1, si->sn_save_cpo);
14863e191694SBram Moolenaar vim_free(si->sn_save_cpo);
14873e191694SBram Moolenaar si->sn_save_cpo = t;
14883e191694SBram Moolenaar }
14893e191694SBram Moolenaar }
14903e191694SBram Moolenaar }
149137294bd6SBram Moolenaar set_option_value((char_u *)"cpo", 0L, si->sn_save_cpo, OPT_NO_REDRAW);
14920123cc1eSBram Moolenaar VIM_CLEAR(si->sn_save_cpo);
14938a7d6542SBram Moolenaar }
14948a7d6542SBram Moolenaar
1495307c5a5bSBram Moolenaar restore_funccal();
1496307c5a5bSBram Moolenaar # ifdef FEAT_PROFILE
1497307c5a5bSBram Moolenaar if (do_profiling == PROF_YES)
1498307c5a5bSBram Moolenaar prof_child_exit(&wait_start); // leaving a child now
1499307c5a5bSBram Moolenaar # endif
1500307c5a5bSBram Moolenaar #endif
15019b8d6226SBram Moolenaar current_sctx = save_current_sctx;
15029b8d6226SBram Moolenaar
1503307c5a5bSBram Moolenaar fclose(cookie.fp);
1504307c5a5bSBram Moolenaar vim_free(cookie.nextline);
1505307c5a5bSBram Moolenaar vim_free(firstline);
1506307c5a5bSBram Moolenaar convert_setup(&cookie.conv, NULL, NULL);
1507307c5a5bSBram Moolenaar
1508307c5a5bSBram Moolenaar if (trigger_source_post)
1509307c5a5bSBram Moolenaar apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
1510307c5a5bSBram Moolenaar
1511307c5a5bSBram Moolenaar theend:
1512307c5a5bSBram Moolenaar vim_free(fname_exp);
1513*8de901e1SBram Moolenaar #ifdef FEAT_EVAL
1514f0a4069eSBram Moolenaar estack_compiling = save_estack_compiling;
1515*8de901e1SBram Moolenaar #endif
1516307c5a5bSBram Moolenaar return retval;
1517307c5a5bSBram Moolenaar }
1518307c5a5bSBram Moolenaar
1519307c5a5bSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
1520307c5a5bSBram Moolenaar
1521307c5a5bSBram Moolenaar /*
1522307c5a5bSBram Moolenaar * ":scriptnames"
1523307c5a5bSBram Moolenaar */
1524307c5a5bSBram Moolenaar void
ex_scriptnames(exarg_T * eap)1525307c5a5bSBram Moolenaar ex_scriptnames(exarg_T *eap)
1526307c5a5bSBram Moolenaar {
1527307c5a5bSBram Moolenaar int i;
1528307c5a5bSBram Moolenaar
1529307c5a5bSBram Moolenaar if (eap->addr_count > 0)
1530307c5a5bSBram Moolenaar {
1531307c5a5bSBram Moolenaar // :script {scriptId}: edit the script
1532e3d4685fSBram Moolenaar if (!SCRIPT_ID_VALID(eap->line2))
1533307c5a5bSBram Moolenaar emsg(_(e_invarg));
1534307c5a5bSBram Moolenaar else
1535307c5a5bSBram Moolenaar {
153621b9e977SBram Moolenaar eap->arg = SCRIPT_ITEM(eap->line2)->sn_name;
1537307c5a5bSBram Moolenaar do_exedit(eap, NULL);
1538307c5a5bSBram Moolenaar }
1539307c5a5bSBram Moolenaar return;
1540307c5a5bSBram Moolenaar }
1541307c5a5bSBram Moolenaar
1542307c5a5bSBram Moolenaar for (i = 1; i <= script_items.ga_len && !got_int; ++i)
154321b9e977SBram Moolenaar if (SCRIPT_ITEM(i)->sn_name != NULL)
1544307c5a5bSBram Moolenaar {
154521b9e977SBram Moolenaar home_replace(NULL, SCRIPT_ITEM(i)->sn_name,
1546307c5a5bSBram Moolenaar NameBuff, MAXPATHL, TRUE);
1547307c5a5bSBram Moolenaar smsg("%3d: %s", i, NameBuff);
1548307c5a5bSBram Moolenaar }
1549307c5a5bSBram Moolenaar }
1550307c5a5bSBram Moolenaar
1551307c5a5bSBram Moolenaar # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
1552307c5a5bSBram Moolenaar /*
1553307c5a5bSBram Moolenaar * Fix slashes in the list of script names for 'shellslash'.
1554307c5a5bSBram Moolenaar */
1555307c5a5bSBram Moolenaar void
scriptnames_slash_adjust(void)1556307c5a5bSBram Moolenaar scriptnames_slash_adjust(void)
1557307c5a5bSBram Moolenaar {
1558307c5a5bSBram Moolenaar int i;
1559307c5a5bSBram Moolenaar
1560307c5a5bSBram Moolenaar for (i = 1; i <= script_items.ga_len; ++i)
156121b9e977SBram Moolenaar if (SCRIPT_ITEM(i)->sn_name != NULL)
156221b9e977SBram Moolenaar slash_adjust(SCRIPT_ITEM(i)->sn_name);
1563307c5a5bSBram Moolenaar }
1564307c5a5bSBram Moolenaar # endif
1565307c5a5bSBram Moolenaar
1566307c5a5bSBram Moolenaar /*
1567307c5a5bSBram Moolenaar * Get a pointer to a script name. Used for ":verbose set".
156874667060SBram Moolenaar * Message appended to "Last set from "
1569307c5a5bSBram Moolenaar */
1570307c5a5bSBram Moolenaar char_u *
get_scriptname(scid_T id)1571307c5a5bSBram Moolenaar get_scriptname(scid_T id)
1572307c5a5bSBram Moolenaar {
1573307c5a5bSBram Moolenaar if (id == SID_MODELINE)
1574307c5a5bSBram Moolenaar return (char_u *)_("modeline");
1575307c5a5bSBram Moolenaar if (id == SID_CMDARG)
1576307c5a5bSBram Moolenaar return (char_u *)_("--cmd argument");
1577307c5a5bSBram Moolenaar if (id == SID_CARG)
1578307c5a5bSBram Moolenaar return (char_u *)_("-c argument");
1579307c5a5bSBram Moolenaar if (id == SID_ENV)
1580307c5a5bSBram Moolenaar return (char_u *)_("environment variable");
1581307c5a5bSBram Moolenaar if (id == SID_ERROR)
1582307c5a5bSBram Moolenaar return (char_u *)_("error handler");
158374667060SBram Moolenaar if (id == SID_WINLAYOUT)
158474667060SBram Moolenaar return (char_u *)_("changed window size");
158521b9e977SBram Moolenaar return SCRIPT_ITEM(id)->sn_name;
1586307c5a5bSBram Moolenaar }
1587307c5a5bSBram Moolenaar
1588307c5a5bSBram Moolenaar # if defined(EXITFREE) || defined(PROTO)
1589307c5a5bSBram Moolenaar void
free_scriptnames(void)1590307c5a5bSBram Moolenaar free_scriptnames(void)
1591307c5a5bSBram Moolenaar {
1592307c5a5bSBram Moolenaar int i;
1593307c5a5bSBram Moolenaar
1594307c5a5bSBram Moolenaar for (i = script_items.ga_len; i > 0; --i)
15958617348eSBram Moolenaar {
159621b9e977SBram Moolenaar scriptitem_T *si = SCRIPT_ITEM(i);
15978a7d6542SBram Moolenaar
159821b9e977SBram Moolenaar // the variables themselves are cleared in evalvars_clear()
159921b9e977SBram Moolenaar vim_free(si->sn_vars);
160021b9e977SBram Moolenaar
160121b9e977SBram Moolenaar vim_free(si->sn_name);
16028d739de4SBram Moolenaar free_imports_and_script_vars(i);
160321b9e977SBram Moolenaar free_string_option(si->sn_save_cpo);
1604a720be78SBram Moolenaar # ifdef FEAT_PROFILE
160521b9e977SBram Moolenaar ga_clear(&si->sn_prl_ga);
1606a720be78SBram Moolenaar # endif
160721b9e977SBram Moolenaar vim_free(si);
16088617348eSBram Moolenaar }
1609307c5a5bSBram Moolenaar ga_clear(&script_items);
1610307c5a5bSBram Moolenaar }
1611da6c0334SBram Moolenaar
1612da6c0334SBram Moolenaar void
free_autoload_scriptnames(void)1613da6c0334SBram Moolenaar free_autoload_scriptnames(void)
1614da6c0334SBram Moolenaar {
1615da6c0334SBram Moolenaar ga_clear_strings(&ga_loaded);
1616da6c0334SBram Moolenaar }
1617307c5a5bSBram Moolenaar # endif
1618307c5a5bSBram Moolenaar
1619307c5a5bSBram Moolenaar #endif
1620307c5a5bSBram Moolenaar
1621307c5a5bSBram Moolenaar linenr_T
get_sourced_lnum(char_u * (* fgetline)(int,void *,int,getline_opt_T),void * cookie)162266250c93SBram Moolenaar get_sourced_lnum(
162366250c93SBram Moolenaar char_u *(*fgetline)(int, void *, int, getline_opt_T),
162466250c93SBram Moolenaar void *cookie)
1625307c5a5bSBram Moolenaar {
1626307c5a5bSBram Moolenaar return fgetline == getsourceline
16279567efa1SBram Moolenaar ? ((source_cookie_T *)cookie)->sourcing_lnum
16281a47ae32SBram Moolenaar : SOURCING_LNUM;
1629307c5a5bSBram Moolenaar }
1630307c5a5bSBram Moolenaar
1631307c5a5bSBram Moolenaar static char_u *
get_one_sourceline(source_cookie_T * sp)16329567efa1SBram Moolenaar get_one_sourceline(source_cookie_T *sp)
1633307c5a5bSBram Moolenaar {
1634307c5a5bSBram Moolenaar garray_T ga;
1635307c5a5bSBram Moolenaar int len;
1636307c5a5bSBram Moolenaar int c;
1637307c5a5bSBram Moolenaar char_u *buf;
1638307c5a5bSBram Moolenaar #ifdef USE_CRNL
1639307c5a5bSBram Moolenaar int has_cr; // CR-LF found
1640307c5a5bSBram Moolenaar #endif
1641307c5a5bSBram Moolenaar int have_read = FALSE;
1642307c5a5bSBram Moolenaar
1643307c5a5bSBram Moolenaar // use a growarray to store the sourced line
1644307c5a5bSBram Moolenaar ga_init2(&ga, 1, 250);
1645307c5a5bSBram Moolenaar
1646307c5a5bSBram Moolenaar // Loop until there is a finished line (or end-of-file).
1647307c5a5bSBram Moolenaar ++sp->sourcing_lnum;
1648307c5a5bSBram Moolenaar for (;;)
1649307c5a5bSBram Moolenaar {
1650307c5a5bSBram Moolenaar // make room to read at least 120 (more) characters
1651307c5a5bSBram Moolenaar if (ga_grow(&ga, 120) == FAIL)
1652307c5a5bSBram Moolenaar break;
1653307c5a5bSBram Moolenaar buf = (char_u *)ga.ga_data;
1654307c5a5bSBram Moolenaar
1655307c5a5bSBram Moolenaar if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
1656307c5a5bSBram Moolenaar sp->fp) == NULL)
1657307c5a5bSBram Moolenaar break;
1658307c5a5bSBram Moolenaar len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
1659307c5a5bSBram Moolenaar #ifdef USE_CRNL
1660307c5a5bSBram Moolenaar // Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
1661307c5a5bSBram Moolenaar // CTRL-Z by its own, or after a NL.
1662307c5a5bSBram Moolenaar if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
1663307c5a5bSBram Moolenaar && sp->fileformat == EOL_DOS
1664307c5a5bSBram Moolenaar && buf[len - 1] == Ctrl_Z)
1665307c5a5bSBram Moolenaar {
1666307c5a5bSBram Moolenaar buf[len - 1] = NUL;
1667307c5a5bSBram Moolenaar break;
1668307c5a5bSBram Moolenaar }
1669307c5a5bSBram Moolenaar #endif
1670307c5a5bSBram Moolenaar
1671307c5a5bSBram Moolenaar have_read = TRUE;
1672307c5a5bSBram Moolenaar ga.ga_len = len;
1673307c5a5bSBram Moolenaar
1674307c5a5bSBram Moolenaar // If the line was longer than the buffer, read more.
1675307c5a5bSBram Moolenaar if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
1676307c5a5bSBram Moolenaar continue;
1677307c5a5bSBram Moolenaar
1678307c5a5bSBram Moolenaar if (len >= 1 && buf[len - 1] == '\n') // remove trailing NL
1679307c5a5bSBram Moolenaar {
1680307c5a5bSBram Moolenaar #ifdef USE_CRNL
1681307c5a5bSBram Moolenaar has_cr = (len >= 2 && buf[len - 2] == '\r');
1682307c5a5bSBram Moolenaar if (sp->fileformat == EOL_UNKNOWN)
1683307c5a5bSBram Moolenaar {
1684307c5a5bSBram Moolenaar if (has_cr)
1685307c5a5bSBram Moolenaar sp->fileformat = EOL_DOS;
1686307c5a5bSBram Moolenaar else
1687307c5a5bSBram Moolenaar sp->fileformat = EOL_UNIX;
1688307c5a5bSBram Moolenaar }
1689307c5a5bSBram Moolenaar
1690307c5a5bSBram Moolenaar if (sp->fileformat == EOL_DOS)
1691307c5a5bSBram Moolenaar {
1692307c5a5bSBram Moolenaar if (has_cr) // replace trailing CR
1693307c5a5bSBram Moolenaar {
1694307c5a5bSBram Moolenaar buf[len - 2] = '\n';
1695307c5a5bSBram Moolenaar --len;
1696307c5a5bSBram Moolenaar --ga.ga_len;
1697307c5a5bSBram Moolenaar }
1698307c5a5bSBram Moolenaar else // lines like ":map xx yy^M" will have failed
1699307c5a5bSBram Moolenaar {
1700307c5a5bSBram Moolenaar if (!sp->error)
1701307c5a5bSBram Moolenaar {
1702307c5a5bSBram Moolenaar msg_source(HL_ATTR(HLF_W));
1703307c5a5bSBram Moolenaar emsg(_("W15: Warning: Wrong line separator, ^M may be missing"));
1704307c5a5bSBram Moolenaar }
1705307c5a5bSBram Moolenaar sp->error = TRUE;
1706307c5a5bSBram Moolenaar sp->fileformat = EOL_UNIX;
1707307c5a5bSBram Moolenaar }
1708307c5a5bSBram Moolenaar }
1709307c5a5bSBram Moolenaar #endif
1710307c5a5bSBram Moolenaar // The '\n' is escaped if there is an odd number of ^V's just
1711307c5a5bSBram Moolenaar // before it, first set "c" just before the 'V's and then check
1712307c5a5bSBram Moolenaar // len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo
1713307c5a5bSBram Moolenaar for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
1714307c5a5bSBram Moolenaar ;
1715307c5a5bSBram Moolenaar if ((len & 1) != (c & 1)) // escaped NL, read more
1716307c5a5bSBram Moolenaar {
1717307c5a5bSBram Moolenaar ++sp->sourcing_lnum;
1718307c5a5bSBram Moolenaar continue;
1719307c5a5bSBram Moolenaar }
1720307c5a5bSBram Moolenaar
1721307c5a5bSBram Moolenaar buf[len - 1] = NUL; // remove the NL
1722307c5a5bSBram Moolenaar }
1723307c5a5bSBram Moolenaar
1724307c5a5bSBram Moolenaar // Check for ^C here now and then, so recursive :so can be broken.
1725307c5a5bSBram Moolenaar line_breakcheck();
1726307c5a5bSBram Moolenaar break;
1727307c5a5bSBram Moolenaar }
1728307c5a5bSBram Moolenaar
1729307c5a5bSBram Moolenaar if (have_read)
1730307c5a5bSBram Moolenaar return (char_u *)ga.ga_data;
1731307c5a5bSBram Moolenaar
1732307c5a5bSBram Moolenaar vim_free(ga.ga_data);
1733307c5a5bSBram Moolenaar return NULL;
1734307c5a5bSBram Moolenaar }
1735307c5a5bSBram Moolenaar
1736307c5a5bSBram Moolenaar /*
1737307c5a5bSBram Moolenaar * Get one full line from a sourced file.
1738307c5a5bSBram Moolenaar * Called by do_cmdline() when it's called from do_source().
1739307c5a5bSBram Moolenaar *
1740307c5a5bSBram Moolenaar * Return a pointer to the line in allocated memory.
1741307c5a5bSBram Moolenaar * Return NULL for end-of-file or some error.
1742307c5a5bSBram Moolenaar */
1743307c5a5bSBram Moolenaar char_u *
getsourceline(int c UNUSED,void * cookie,int indent UNUSED,getline_opt_T options)174466250c93SBram Moolenaar getsourceline(
174566250c93SBram Moolenaar int c UNUSED,
174666250c93SBram Moolenaar void *cookie,
174766250c93SBram Moolenaar int indent UNUSED,
174866250c93SBram Moolenaar getline_opt_T options)
1749307c5a5bSBram Moolenaar {
17509567efa1SBram Moolenaar source_cookie_T *sp = (source_cookie_T *)cookie;
1751307c5a5bSBram Moolenaar char_u *line;
1752307c5a5bSBram Moolenaar char_u *p;
1753dcc58e03SBram Moolenaar int do_vim9_all = in_vim9script()
1754dcc58e03SBram Moolenaar && options == GETLINE_CONCAT_ALL;
17558242ebbdSBram Moolenaar int do_bar_cont = do_vim9_all
17568242ebbdSBram Moolenaar || options == GETLINE_CONCAT_CONTBAR;
1757307c5a5bSBram Moolenaar
1758307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1759307c5a5bSBram Moolenaar // If breakpoints have been added/deleted need to check for it.
1760307c5a5bSBram Moolenaar if (sp->dbg_tick < debug_tick)
1761307c5a5bSBram Moolenaar {
17621a47ae32SBram Moolenaar sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
1763307c5a5bSBram Moolenaar sp->dbg_tick = debug_tick;
1764307c5a5bSBram Moolenaar }
1765307c5a5bSBram Moolenaar # ifdef FEAT_PROFILE
1766307c5a5bSBram Moolenaar if (do_profiling == PROF_YES)
1767307c5a5bSBram Moolenaar script_line_end();
1768307c5a5bSBram Moolenaar # endif
1769307c5a5bSBram Moolenaar #endif
1770307c5a5bSBram Moolenaar
1771307c5a5bSBram Moolenaar // Set the current sourcing line number.
17721a47ae32SBram Moolenaar SOURCING_LNUM = sp->sourcing_lnum + 1;
1773307c5a5bSBram Moolenaar
1774307c5a5bSBram Moolenaar // Get current line. If there is a read-ahead line, use it, otherwise get
17759567efa1SBram Moolenaar // one now. "fp" is NULL if actually using a string.
17769567efa1SBram Moolenaar if (sp->finished || sp->fp == NULL)
1777307c5a5bSBram Moolenaar line = NULL;
1778307c5a5bSBram Moolenaar else if (sp->nextline == NULL)
1779307c5a5bSBram Moolenaar line = get_one_sourceline(sp);
1780307c5a5bSBram Moolenaar else
1781307c5a5bSBram Moolenaar {
1782307c5a5bSBram Moolenaar line = sp->nextline;
1783307c5a5bSBram Moolenaar sp->nextline = NULL;
1784307c5a5bSBram Moolenaar ++sp->sourcing_lnum;
1785307c5a5bSBram Moolenaar }
1786307c5a5bSBram Moolenaar #ifdef FEAT_PROFILE
1787307c5a5bSBram Moolenaar if (line != NULL && do_profiling == PROF_YES)
1788307c5a5bSBram Moolenaar script_line_start();
1789307c5a5bSBram Moolenaar #endif
1790307c5a5bSBram Moolenaar
1791307c5a5bSBram Moolenaar // Only concatenate lines starting with a \ when 'cpoptions' doesn't
1792307c5a5bSBram Moolenaar // contain the 'C' flag.
179366250c93SBram Moolenaar if (line != NULL && options != GETLINE_NONE
179466250c93SBram Moolenaar && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
1795307c5a5bSBram Moolenaar {
17965072b47aSBram Moolenaar int comment_char = in_vim9script() ? '#' : '"';
17975072b47aSBram Moolenaar
1798307c5a5bSBram Moolenaar // compensate for the one line read-ahead
1799307c5a5bSBram Moolenaar --sp->sourcing_lnum;
1800307c5a5bSBram Moolenaar
1801307c5a5bSBram Moolenaar // Get the next line and concatenate it when it starts with a
1802307c5a5bSBram Moolenaar // backslash. We always need to read the next line, keep it in
1803307c5a5bSBram Moolenaar // sp->nextline.
1804307c5a5bSBram Moolenaar /* Also check for a comment in between continuation lines: "\ */
1805dcc58e03SBram Moolenaar // Also check for a Vim9 comment, empty line, line starting with '|',
1806dcc58e03SBram Moolenaar // but not "||".
1807307c5a5bSBram Moolenaar sp->nextline = get_one_sourceline(sp);
1808307c5a5bSBram Moolenaar if (sp->nextline != NULL
1809307c5a5bSBram Moolenaar && (*(p = skipwhite(sp->nextline)) == '\\'
18105072b47aSBram Moolenaar || (p[0] == comment_char
18115072b47aSBram Moolenaar && p[1] == '\\' && p[2] == ' ')
1812dcc58e03SBram Moolenaar || (do_vim9_all && (*p == NUL
1813dcc58e03SBram Moolenaar || vim9_comment_start(p)))
18148242ebbdSBram Moolenaar || (do_bar_cont && p[0] == '|' && p[1] != '|')))
1815307c5a5bSBram Moolenaar {
1816307c5a5bSBram Moolenaar garray_T ga;
1817307c5a5bSBram Moolenaar
1818307c5a5bSBram Moolenaar ga_init2(&ga, (int)sizeof(char_u), 400);
1819307c5a5bSBram Moolenaar ga_concat(&ga, line);
1820307c5a5bSBram Moolenaar if (*p == '\\')
1821307c5a5bSBram Moolenaar ga_concat(&ga, p + 1);
1822dcc58e03SBram Moolenaar else if (*p == '|')
1823dcc58e03SBram Moolenaar {
1824dcc58e03SBram Moolenaar ga_concat(&ga, (char_u *)" ");
1825dcc58e03SBram Moolenaar ga_concat(&ga, p);
1826dcc58e03SBram Moolenaar }
1827307c5a5bSBram Moolenaar for (;;)
1828307c5a5bSBram Moolenaar {
1829307c5a5bSBram Moolenaar vim_free(sp->nextline);
1830307c5a5bSBram Moolenaar sp->nextline = get_one_sourceline(sp);
1831307c5a5bSBram Moolenaar if (sp->nextline == NULL)
1832307c5a5bSBram Moolenaar break;
1833307c5a5bSBram Moolenaar p = skipwhite(sp->nextline);
18348242ebbdSBram Moolenaar if (*p == '\\' || (do_bar_cont && p[0] == '|' && p[1] != '|'))
1835307c5a5bSBram Moolenaar {
1836307c5a5bSBram Moolenaar // Adjust the growsize to the current length to speed up
1837307c5a5bSBram Moolenaar // concatenating many lines.
1838307c5a5bSBram Moolenaar if (ga.ga_len > 400)
1839307c5a5bSBram Moolenaar {
1840307c5a5bSBram Moolenaar if (ga.ga_len > 8000)
1841307c5a5bSBram Moolenaar ga.ga_growsize = 8000;
1842307c5a5bSBram Moolenaar else
1843307c5a5bSBram Moolenaar ga.ga_growsize = ga.ga_len;
1844307c5a5bSBram Moolenaar }
1845dcc58e03SBram Moolenaar if (*p == '\\')
1846307c5a5bSBram Moolenaar ga_concat(&ga, p + 1);
1847dcc58e03SBram Moolenaar else
1848dcc58e03SBram Moolenaar {
1849dcc58e03SBram Moolenaar ga_concat(&ga, (char_u *)" ");
1850dcc58e03SBram Moolenaar ga_concat(&ga, p);
1851dcc58e03SBram Moolenaar }
1852307c5a5bSBram Moolenaar }
18535072b47aSBram Moolenaar else if (!(p[0] == (comment_char)
18540f37e356SBram Moolenaar && p[1] == '\\' && p[2] == ' ')
1855dcc58e03SBram Moolenaar && !(do_vim9_all && (*p == NUL || vim9_comment_start(p))))
1856307c5a5bSBram Moolenaar break;
185775783bd8SBram Moolenaar /* drop a # comment or "\ comment line */
1858307c5a5bSBram Moolenaar }
1859307c5a5bSBram Moolenaar ga_append(&ga, NUL);
1860307c5a5bSBram Moolenaar vim_free(line);
1861307c5a5bSBram Moolenaar line = ga.ga_data;
1862307c5a5bSBram Moolenaar }
1863307c5a5bSBram Moolenaar }
1864307c5a5bSBram Moolenaar
1865307c5a5bSBram Moolenaar if (line != NULL && sp->conv.vc_type != CONV_NONE)
1866307c5a5bSBram Moolenaar {
1867307c5a5bSBram Moolenaar char_u *s;
1868307c5a5bSBram Moolenaar
1869307c5a5bSBram Moolenaar // Convert the encoding of the script line.
1870307c5a5bSBram Moolenaar s = string_convert(&sp->conv, line, NULL);
1871307c5a5bSBram Moolenaar if (s != NULL)
1872307c5a5bSBram Moolenaar {
1873307c5a5bSBram Moolenaar vim_free(line);
1874307c5a5bSBram Moolenaar line = s;
1875307c5a5bSBram Moolenaar }
1876307c5a5bSBram Moolenaar }
1877307c5a5bSBram Moolenaar
1878307c5a5bSBram Moolenaar #ifdef FEAT_EVAL
1879307c5a5bSBram Moolenaar // Did we encounter a breakpoint?
18801a47ae32SBram Moolenaar if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM)
1881307c5a5bSBram Moolenaar {
18821a47ae32SBram Moolenaar dbg_breakpoint(sp->fname, SOURCING_LNUM);
1883307c5a5bSBram Moolenaar // Find next breakpoint.
18841a47ae32SBram Moolenaar sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
1885307c5a5bSBram Moolenaar sp->dbg_tick = debug_tick;
1886307c5a5bSBram Moolenaar }
1887307c5a5bSBram Moolenaar #endif
1888307c5a5bSBram Moolenaar
1889307c5a5bSBram Moolenaar return line;
1890307c5a5bSBram Moolenaar }
1891307c5a5bSBram Moolenaar
1892307c5a5bSBram Moolenaar /*
1893307c5a5bSBram Moolenaar * ":scriptencoding": Set encoding conversion for a sourced script.
1894307c5a5bSBram Moolenaar */
1895307c5a5bSBram Moolenaar void
ex_scriptencoding(exarg_T * eap)1896307c5a5bSBram Moolenaar ex_scriptencoding(exarg_T *eap)
1897307c5a5bSBram Moolenaar {
18989567efa1SBram Moolenaar source_cookie_T *sp;
1899307c5a5bSBram Moolenaar char_u *name;
1900307c5a5bSBram Moolenaar
1901307c5a5bSBram Moolenaar if (!getline_equal(eap->getline, eap->cookie, getsourceline))
1902307c5a5bSBram Moolenaar {
1903307c5a5bSBram Moolenaar emsg(_("E167: :scriptencoding used outside of a sourced file"));
1904307c5a5bSBram Moolenaar return;
1905307c5a5bSBram Moolenaar }
1906307c5a5bSBram Moolenaar
1907307c5a5bSBram Moolenaar if (*eap->arg != NUL)
1908307c5a5bSBram Moolenaar {
1909307c5a5bSBram Moolenaar name = enc_canonize(eap->arg);
1910307c5a5bSBram Moolenaar if (name == NULL) // out of memory
1911307c5a5bSBram Moolenaar return;
1912307c5a5bSBram Moolenaar }
1913307c5a5bSBram Moolenaar else
1914307c5a5bSBram Moolenaar name = eap->arg;
1915307c5a5bSBram Moolenaar
1916307c5a5bSBram Moolenaar // Setup for conversion from the specified encoding to 'encoding'.
19179567efa1SBram Moolenaar sp = (source_cookie_T *)getline_cookie(eap->getline, eap->cookie);
1918307c5a5bSBram Moolenaar convert_setup(&sp->conv, name, p_enc);
1919307c5a5bSBram Moolenaar
1920307c5a5bSBram Moolenaar if (name != eap->arg)
1921307c5a5bSBram Moolenaar vim_free(name);
1922307c5a5bSBram Moolenaar }
1923307c5a5bSBram Moolenaar
1924307c5a5bSBram Moolenaar /*
1925307c5a5bSBram Moolenaar * ":scriptversion": Set Vim script version for a sourced script.
1926307c5a5bSBram Moolenaar */
1927307c5a5bSBram Moolenaar void
ex_scriptversion(exarg_T * eap UNUSED)1928307c5a5bSBram Moolenaar ex_scriptversion(exarg_T *eap UNUSED)
1929307c5a5bSBram Moolenaar {
1930307c5a5bSBram Moolenaar int nr;
1931307c5a5bSBram Moolenaar
1932307c5a5bSBram Moolenaar if (!getline_equal(eap->getline, eap->cookie, getsourceline))
1933307c5a5bSBram Moolenaar {
1934307c5a5bSBram Moolenaar emsg(_("E984: :scriptversion used outside of a sourced file"));
1935307c5a5bSBram Moolenaar return;
1936307c5a5bSBram Moolenaar }
1937eb6880b6SBram Moolenaar if (in_vim9script())
19388a7d6542SBram Moolenaar {
1939451c2e35SBram Moolenaar emsg(_(e_cannot_use_scriptversion_after_vim9script));
19408a7d6542SBram Moolenaar return;
19418a7d6542SBram Moolenaar }
1942307c5a5bSBram Moolenaar
1943307c5a5bSBram Moolenaar nr = getdigits(&eap->arg);
1944307c5a5bSBram Moolenaar if (nr == 0 || *eap->arg != NUL)
1945307c5a5bSBram Moolenaar emsg(_(e_invarg));
19466797966dSBram Moolenaar else if (nr > SCRIPT_VERSION_MAX)
1947307c5a5bSBram Moolenaar semsg(_("E999: scriptversion not supported: %d"), nr);
1948307c5a5bSBram Moolenaar else
19497ebcba61SBram Moolenaar {
1950307c5a5bSBram Moolenaar current_sctx.sc_version = nr;
19519b8d6226SBram Moolenaar #ifdef FEAT_EVAL
195221b9e977SBram Moolenaar SCRIPT_ITEM(current_sctx.sc_sid)->sn_version = nr;
1953307c5a5bSBram Moolenaar #endif
1954307c5a5bSBram Moolenaar }
19559b8d6226SBram Moolenaar }
1956307c5a5bSBram Moolenaar
1957307c5a5bSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
1958307c5a5bSBram Moolenaar /*
1959307c5a5bSBram Moolenaar * ":finish": Mark a sourced file as finished.
1960307c5a5bSBram Moolenaar */
1961307c5a5bSBram Moolenaar void
ex_finish(exarg_T * eap)1962307c5a5bSBram Moolenaar ex_finish(exarg_T *eap)
1963307c5a5bSBram Moolenaar {
1964307c5a5bSBram Moolenaar if (getline_equal(eap->getline, eap->cookie, getsourceline))
1965307c5a5bSBram Moolenaar do_finish(eap, FALSE);
1966307c5a5bSBram Moolenaar else
1967307c5a5bSBram Moolenaar emsg(_("E168: :finish used outside of a sourced file"));
1968307c5a5bSBram Moolenaar }
1969307c5a5bSBram Moolenaar
1970307c5a5bSBram Moolenaar /*
1971307c5a5bSBram Moolenaar * Mark a sourced file as finished. Possibly makes the ":finish" pending.
1972307c5a5bSBram Moolenaar * Also called for a pending finish at the ":endtry" or after returning from
1973307c5a5bSBram Moolenaar * an extra do_cmdline(). "reanimate" is used in the latter case.
1974307c5a5bSBram Moolenaar */
1975307c5a5bSBram Moolenaar void
do_finish(exarg_T * eap,int reanimate)1976307c5a5bSBram Moolenaar do_finish(exarg_T *eap, int reanimate)
1977307c5a5bSBram Moolenaar {
1978307c5a5bSBram Moolenaar int idx;
1979307c5a5bSBram Moolenaar
1980307c5a5bSBram Moolenaar if (reanimate)
19819567efa1SBram Moolenaar ((source_cookie_T *)getline_cookie(eap->getline,
1982307c5a5bSBram Moolenaar eap->cookie))->finished = FALSE;
1983307c5a5bSBram Moolenaar
1984307c5a5bSBram Moolenaar // Cleanup (and inactivate) conditionals, but stop when a try conditional
1985307c5a5bSBram Moolenaar // not in its finally clause (which then is to be executed next) is found.
1986307c5a5bSBram Moolenaar // In this case, make the ":finish" pending for execution at the ":endtry".
1987307c5a5bSBram Moolenaar // Otherwise, finish normally.
1988307c5a5bSBram Moolenaar idx = cleanup_conditionals(eap->cstack, 0, TRUE);
1989307c5a5bSBram Moolenaar if (idx >= 0)
1990307c5a5bSBram Moolenaar {
1991307c5a5bSBram Moolenaar eap->cstack->cs_pending[idx] = CSTP_FINISH;
1992307c5a5bSBram Moolenaar report_make_pending(CSTP_FINISH, NULL);
1993307c5a5bSBram Moolenaar }
1994307c5a5bSBram Moolenaar else
19959567efa1SBram Moolenaar ((source_cookie_T *)getline_cookie(eap->getline,
1996307c5a5bSBram Moolenaar eap->cookie))->finished = TRUE;
1997307c5a5bSBram Moolenaar }
1998307c5a5bSBram Moolenaar
1999307c5a5bSBram Moolenaar
2000307c5a5bSBram Moolenaar /*
2001307c5a5bSBram Moolenaar * Return TRUE when a sourced file had the ":finish" command: Don't give error
2002307c5a5bSBram Moolenaar * message for missing ":endif".
2003307c5a5bSBram Moolenaar * Return FALSE when not sourcing a file.
2004307c5a5bSBram Moolenaar */
2005307c5a5bSBram Moolenaar int
source_finished(char_u * (* fgetline)(int,void *,int,getline_opt_T),void * cookie)2006307c5a5bSBram Moolenaar source_finished(
200766250c93SBram Moolenaar char_u *(*fgetline)(int, void *, int, getline_opt_T),
2008307c5a5bSBram Moolenaar void *cookie)
2009307c5a5bSBram Moolenaar {
2010307c5a5bSBram Moolenaar return (getline_equal(fgetline, cookie, getsourceline)
20119567efa1SBram Moolenaar && ((source_cookie_T *)getline_cookie(
2012307c5a5bSBram Moolenaar fgetline, cookie))->finished);
2013307c5a5bSBram Moolenaar }
2014da6c0334SBram Moolenaar
2015da6c0334SBram Moolenaar /*
2016da6c0334SBram Moolenaar * Return the autoload script name for a function or variable name.
2017da6c0334SBram Moolenaar * Returns NULL when out of memory.
2018da6c0334SBram Moolenaar * Caller must make sure that "name" contains AUTOLOAD_CHAR.
2019da6c0334SBram Moolenaar */
2020da6c0334SBram Moolenaar char_u *
autoload_name(char_u * name)2021da6c0334SBram Moolenaar autoload_name(char_u *name)
2022da6c0334SBram Moolenaar {
2023da6c0334SBram Moolenaar char_u *p, *q = NULL;
2024da6c0334SBram Moolenaar char_u *scriptname;
2025da6c0334SBram Moolenaar
2026da6c0334SBram Moolenaar // Get the script file name: replace '#' with '/', append ".vim".
2027da6c0334SBram Moolenaar scriptname = alloc(STRLEN(name) + 14);
2028da6c0334SBram Moolenaar if (scriptname == NULL)
2029da6c0334SBram Moolenaar return NULL;
2030da6c0334SBram Moolenaar STRCPY(scriptname, "autoload/");
2031a177344dSBram Moolenaar STRCAT(scriptname, name[0] == 'g' && name[1] == ':' ? name + 2: name);
2032da6c0334SBram Moolenaar for (p = scriptname + 9; (p = vim_strchr(p, AUTOLOAD_CHAR)) != NULL;
2033da6c0334SBram Moolenaar q = p, ++p)
2034da6c0334SBram Moolenaar *p = '/';
2035da6c0334SBram Moolenaar STRCPY(q, ".vim");
2036da6c0334SBram Moolenaar return scriptname;
2037da6c0334SBram Moolenaar }
2038da6c0334SBram Moolenaar
2039da6c0334SBram Moolenaar /*
2040da6c0334SBram Moolenaar * If "name" has a package name try autoloading the script for it.
2041da6c0334SBram Moolenaar * Return TRUE if a package was loaded.
2042da6c0334SBram Moolenaar */
2043da6c0334SBram Moolenaar int
script_autoload(char_u * name,int reload)2044da6c0334SBram Moolenaar script_autoload(
2045da6c0334SBram Moolenaar char_u *name,
2046da6c0334SBram Moolenaar int reload) // load script again when already loaded
2047da6c0334SBram Moolenaar {
2048da6c0334SBram Moolenaar char_u *p;
2049da6c0334SBram Moolenaar char_u *scriptname, *tofree;
2050da6c0334SBram Moolenaar int ret = FALSE;
2051da6c0334SBram Moolenaar int i;
2052daa2f365SBram Moolenaar int ret_sid;
2053da6c0334SBram Moolenaar
2054da6c0334SBram Moolenaar // If there is no '#' after name[0] there is no package name.
2055da6c0334SBram Moolenaar p = vim_strchr(name, AUTOLOAD_CHAR);
2056da6c0334SBram Moolenaar if (p == NULL || p == name)
2057da6c0334SBram Moolenaar return FALSE;
2058da6c0334SBram Moolenaar
2059da6c0334SBram Moolenaar tofree = scriptname = autoload_name(name);
2060da6c0334SBram Moolenaar if (scriptname == NULL)
2061da6c0334SBram Moolenaar return FALSE;
2062da6c0334SBram Moolenaar
2063da6c0334SBram Moolenaar // Find the name in the list of previously loaded package names. Skip
2064da6c0334SBram Moolenaar // "autoload/", it's always the same.
2065da6c0334SBram Moolenaar for (i = 0; i < ga_loaded.ga_len; ++i)
2066da6c0334SBram Moolenaar if (STRCMP(((char_u **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0)
2067da6c0334SBram Moolenaar break;
2068da6c0334SBram Moolenaar if (!reload && i < ga_loaded.ga_len)
2069da6c0334SBram Moolenaar ret = FALSE; // was loaded already
2070da6c0334SBram Moolenaar else
2071da6c0334SBram Moolenaar {
2072da6c0334SBram Moolenaar // Remember the name if it wasn't loaded already.
2073da6c0334SBram Moolenaar if (i == ga_loaded.ga_len && ga_grow(&ga_loaded, 1) == OK)
2074da6c0334SBram Moolenaar {
2075da6c0334SBram Moolenaar ((char_u **)ga_loaded.ga_data)[ga_loaded.ga_len++] = scriptname;
2076da6c0334SBram Moolenaar tofree = NULL;
2077da6c0334SBram Moolenaar }
2078da6c0334SBram Moolenaar
2079da6c0334SBram Moolenaar // Try loading the package from $VIMRUNTIME/autoload/<name>.vim
2080daa2f365SBram Moolenaar // Use "ret_sid" to avoid loading the same script again.
2081daa2f365SBram Moolenaar if (source_in_path(p_rtp, scriptname, 0, &ret_sid) == OK)
2082da6c0334SBram Moolenaar ret = TRUE;
2083da6c0334SBram Moolenaar }
2084da6c0334SBram Moolenaar
2085da6c0334SBram Moolenaar vim_free(tofree);
2086da6c0334SBram Moolenaar return ret;
2087da6c0334SBram Moolenaar }
2088307c5a5bSBram Moolenaar #endif
2089