On Mo, 29 Okt 2018, Bram Moolenaar wrote:

> Christian wrote:
> 
> > Okay, how about this patch:
> 
> Thanks.  It would be helpful to add a few comments.  E.g., why is the
> buffer size sufficient?  I suppose because home_replace() can only make
> it shorter (is that actually true?).

Yes, it was my understanding of the home_replace() function, that the 
result can only be shorter (if it replaced anything, else the buffer 
would not be modified).

> And splitting it in parts with += is probably needed to avoid running
> into MAXPATHL when reading back the option value, right?

Yes and it made the result look a bit cleaner.

Attached is an updated patch (it just adds comments)

Best,
Christian
-- 
Das Problem der Tretminen läßt sich nur Schritt für Schritt lösen.
                -- Helmut Kohl

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
commit 6e464b9ad44fc3199d841cfbe977b53ffd493fd6
Author: Christian Brabandt <[email protected]>
Date:   Tue Oct 30 08:37:14 2018 +0100

    Write long &rtp path corretly in the session file
    
    vim/vim#3466

diff --git a/src/option.c b/src/option.c
index 7934ee6ed..7eb713e19 100644
--- a/src/option.c
+++ b/src/option.c
@@ -3315,7 +3315,7 @@ static int find_key_option(char_u *arg_arg, int has_lt);
 static void showoptions(int all, int opt_flags);
 static int optval_default(struct vimoption *, char_u *varp);
 static void showoneopt(struct vimoption *, int opt_flags);
-static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, int expand);
+static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, long flags);
 static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep);
 static int put_setbool(FILE *fd, char *cmd, char *name, int value);
 static int  istermoption(struct vimoption *);
@@ -10324,7 +10324,7 @@ makeset(FILE *fd, int opt_flags, int local_only)
 			do_endif = TRUE;
 		    }
 		    if (put_setstring(fd, cmd, p->fullname, (char_u **)varp,
-					  (p->flags & P_EXPAND) != 0) == FAIL)
+					  p->flags) == FAIL)
 			return FAIL;
 		    if (do_endif)
 		    {
@@ -10372,10 +10372,11 @@ put_setstring(
     char	*cmd,
     char	*name,
     char_u	**valuep,
-    int		expand)
+    long	flags)
 {
     char_u	*s;
     char_u	*buf;
+    char_u	*p,*q;
 
     if (fprintf(fd, "%s %s=", cmd, name) < 0)
 	return FAIL;
@@ -10391,12 +10392,43 @@ put_setstring(
 		if (put_escstr(fd, str2special(&s, FALSE), 2) == FAIL)
 		    return FAIL;
 	}
-	else if (expand)
+	// expand the option value, replace $HOME by ~
+	else if ((flags & P_EXPAND) != 0)
 	{
-	    buf = alloc(MAXPATHL);
-	    if (buf == NULL)
+	    size_t  size = STRLEN(*valuep) + 1;
+	    // p stores the expanded option value
+	    // buf, stores one (expanded) option value part
+	    buf = alloc(size);
+	    p = vim_strsave(*valuep);
+	    if (buf == NULL || p == NULL)
 		return FAIL;
-	    home_replace(NULL, *valuep, buf, MAXPATHL, FALSE);
+	    // remember initial pointer value, needed for freeing later
+	    s = *valuep;
+	    q = p;
+	    // if the option value is longer than MAXPATHL, we need to take
+	    // special care that the value will be written out correctly and
+	    // can be correctly restored, when the session file is read back
+	    if (STRLEN(s) > MAXPATHL && (flags & P_COMMA) != 0
+		    && vim_strchr(*valuep, ',') != NULL)
+	    {
+		// clear option value, e.g. ':set rtp='
+		if (put_eol(fd) == FAIL)
+		    goto fail;
+		home_replace(NULL, s, p, size, FALSE);
+		while (*p != NUL)
+		{
+		    // for each option part, append value to the option, :set rtp+=value
+		    if (fprintf(fd, "%s %s+=", cmd, name) < 0)
+			goto fail;
+		    (void)copy_option_part(&p, buf, size,  ",");
+		    if (put_escstr(fd, buf, 2) == FAIL || put_eol(fd) == FAIL)
+			goto fail;
+		}
+		vim_free(buf);
+		vim_free(q);
+		return OK;
+	    }
+	    home_replace(NULL, *valuep, buf, size, FALSE);
 	    if (put_escstr(fd, buf, 2) == FAIL)
 	    {
 		vim_free(buf);
@@ -10410,6 +10442,10 @@ put_setstring(
     if (put_eol(fd) < 0)
 	return FAIL;
     return OK;
+fail:
+    vim_free(buf);
+    vim_free(q);
+    return FAIL;
 }
 
     static int
diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim
index fa08685ac..1d042b623 100644
--- a/src/testdir/test_mksession.vim
+++ b/src/testdir/test_mksession.vim
@@ -126,6 +126,29 @@ func Test_mksession_large_winheight()
   call delete('Xtest_mks_winheight.out')
 endfunc
 
+func Test_mksession_rtp()
+  new
+  let _rtp=&rtp
+  " Make a real long (invalid) runtimepath value,
+  " that should exceed PATH_MAX (hopefully)
+  let newrtp=&rtp.',~'.repeat('/foobar', 1000)
+  let newrtp.=",".expand("$HOME")."/.vim"
+  let &rtp=newrtp
+
+  " determine expected value
+  let expected=split(&rtp, ',')
+  let expected = map(expected, '"set runtimepath+=".v:val')
+  let expected = ['set runtimepath='] + expected
+  let expected = map(expected, {v,w -> substitute(w, $HOME, "~", "g")})
+
+  mksession! Xtest_mks.out
+  let &rtp=_rtp
+  let li = filter(readfile('Xtest_mks.out'), 'v:val =~# "runtimepath"')
+  call assert_equal(expected, li)
+
+  call delete('Xtest_mks.out')
+endfunc
+
 func Test_mksession_arglist()
   argdel *
   next file1 file2 file3 file4

Raspunde prin e-mail lui