patch 9.0.0253: a symlink to an autoload script results in two entries

Problem:    A symlink to an autoload script results in two entries in the list
            of scripts, items expected in one are actually in the other.
Solution:   Have one script item refer to the actually sourced one.
            (closes #10960)
diff --git a/src/scriptfile.c b/src/scriptfile.c
index c176763..48e475b 100644
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -1357,6 +1357,7 @@
 {
     source_cookie_T	    cookie;
     char_u		    *p;
+    char_u		    *fname_not_fixed = NULL;
     char_u		    *fname_exp;
     char_u		    *firstline = NULL;
     int			    retval = FAIL;
@@ -1389,13 +1390,12 @@
     }
     else
     {
-	p = expand_env_save(fname);
-	if (p == NULL)
-	    return retval;
-	fname_exp = fix_fname(p);
-	vim_free(p);
+	fname_not_fixed = expand_env_save(fname);
+	if (fname_not_fixed == NULL)
+	    goto theend;
+	fname_exp = fix_fname(fname_not_fixed);
 	if (fname_exp == NULL)
-	    return retval;
+	    goto theend;
 	if (mch_isdir(fname_exp))
 	{
 	    smsg(_("Cannot source a directory: \"%s\""), fname);
@@ -1602,14 +1602,15 @@
 	int error = OK;
 
 	// It's new, generate a new SID and initialize the scriptitem.
-	current_sctx.sc_sid = get_new_scriptitem(&error);
+	sid = get_new_scriptitem(&error);
+	current_sctx.sc_sid = sid;
 	if (error == FAIL)
 	    goto almosttheend;
-	si = SCRIPT_ITEM(current_sctx.sc_sid);
+	si = SCRIPT_ITEM(sid);
 	si->sn_name = fname_exp;
 	fname_exp = vim_strsave(si->sn_name);  // used for autocmd
 	if (ret_sid != NULL)
-	    *ret_sid = current_sctx.sc_sid;
+	    *ret_sid = sid;
 
 	// Remember the "is_vimrc" flag for when the file is sourced again.
 	si->sn_is_vimrc = is_vimrc;
@@ -1668,7 +1669,7 @@
     if (do_profiling == PROF_YES)
     {
 	// Get "si" again, "script_items" may have been reallocated.
-	si = SCRIPT_ITEM(current_sctx.sc_sid);
+	si = SCRIPT_ITEM(sid);
 	if (si->sn_prof_on)
 	{
 	    profile_end(&si->sn_pr_start);
@@ -1719,7 +1720,7 @@
     // If "sn_save_cpo" is set that means we encountered "vim9script": restore
     // 'cpoptions', unless in the main .vimrc file.
     // Get "si" again, "script_items" may have been reallocated.
-    si = SCRIPT_ITEM(current_sctx.sc_sid);
+    si = SCRIPT_ITEM(sid);
     if (si->sn_save_cpo != NULL && si->sn_is_vimrc == DOSO_NONE)
     {
 	if (STRCMP(p_cpo, CPO_VIM) != 0)
@@ -1774,6 +1775,19 @@
 	apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
 
 theend:
+    if (sid > 0 && ret_sid != NULL
+	    && fname_not_fixed != NULL && fname_exp != NULL)
+    {
+	int not_fixed_sid = find_script_by_name(fname_not_fixed);
+
+	// If "fname_not_fixed" is a symlink then we source the linked file.
+	// If the original name is in the script list we add the ID of the
+	// script that was actually sourced.
+	if (SCRIPT_ID_VALID(not_fixed_sid) && not_fixed_sid != sid)
+	    SCRIPT_ITEM(not_fixed_sid)->sn_sourced_sid = sid;
+    }
+
+    vim_free(fname_not_fixed);
     vim_free(fname_exp);
     sticky_cmdmod_flags = save_sticky_cmdmod_flags;
 #ifdef FEAT_EVAL
@@ -1787,7 +1801,7 @@
     char_u	*fname,
     int		check_other,	    // check for .vimrc and _vimrc
     int		is_vimrc,	    // DOSO_ value
-    int		*ret_sid UNUSED)
+    int		*ret_sid)
 {
     return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
 }
@@ -1828,9 +1842,16 @@
 
 	if (si->sn_name != NULL)
 	{
+	    char sourced_buf[20];
+
 	    home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, TRUE);
-	    vim_snprintf((char *)IObuff, IOSIZE, "%3d%s: %s",
+	    if (si->sn_sourced_sid > 0)
+		vim_snprintf(sourced_buf, 20, "->%d", si->sn_sourced_sid);
+	    else
+		sourced_buf[0] = NUL;
+	    vim_snprintf((char *)IObuff, IOSIZE, "%3d%s%s: %s",
 		    i,
+		    sourced_buf,
 		    si->sn_state == SN_STATE_NOT_LOADED ? " A" : "",
 		    NameBuff);
 	    if (!message_filtered(IObuff))
@@ -1946,6 +1967,7 @@
 		|| list_append_dict(l, d) == FAIL
 		|| dict_add_string(d, "name", si->sn_name) == FAIL
 		|| dict_add_number(d, "sid", i) == FAIL
+		|| dict_add_number(d, "sourced", si->sn_sourced_sid) == FAIL
 		|| dict_add_bool(d, "autoload",
 				si->sn_state == SN_STATE_NOT_LOADED) == FAIL)
 	    return;