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