xref: /vim-8.2.3635/src/scriptfile.c (revision 8de901e1)
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