diff src/eval.c @ 17966:46f95606b9ec v8.1.1979

patch 8.1.1979: code for handling file names is spread out Commit: https://github.com/vim/vim/commit/b005cd80cfda591be95146024d9b97eef383500f Author: Bram Moolenaar <Bram@vim.org> Date: Wed Sep 4 15:54:55 2019 +0200 patch 8.1.1979: code for handling file names is spread out Problem: Code for handling file names is spread out. Solution: Move code to new filepath.c file. Graduate FEAT_MODIFY_FNAME.
author Bram Moolenaar <Bram@vim.org>
date Wed, 04 Sep 2019 16:00:04 +0200
parents 6d4d3bce365d
children a6d218f99ff7
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -6387,650 +6387,7 @@ typval_tostring(typval_T *arg)
     return ret;
 }
 
-#endif /* FEAT_EVAL */
-
-#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) || defined(PROTO)
-
-#ifdef MSWIN
-/*
- * Functions for ":8" filename modifier: get 8.3 version of a filename.
- */
-
-/*
- * Get the short path (8.3) for the filename in "fnamep".
- * Only works for a valid file name.
- * When the path gets longer "fnamep" is changed and the allocated buffer
- * is put in "bufp".
- * *fnamelen is the length of "fnamep" and set to 0 for a nonexistent path.
- * Returns OK on success, FAIL on failure.
- */
-    static int
-get_short_pathname(char_u **fnamep, char_u **bufp, int *fnamelen)
-{
-    int		l, len;
-    char_u	*newbuf;
-
-    len = *fnamelen;
-    l = GetShortPathName((LPSTR)*fnamep, (LPSTR)*fnamep, len);
-    if (l > len - 1)
-    {
-	/* If that doesn't work (not enough space), then save the string
-	 * and try again with a new buffer big enough. */
-	newbuf = vim_strnsave(*fnamep, l);
-	if (newbuf == NULL)
-	    return FAIL;
-
-	vim_free(*bufp);
-	*fnamep = *bufp = newbuf;
-
-	/* Really should always succeed, as the buffer is big enough. */
-	l = GetShortPathName((LPSTR)*fnamep, (LPSTR)*fnamep, l+1);
-    }
-
-    *fnamelen = l;
-    return OK;
-}
-
-/*
- * Get the short path (8.3) for the filename in "fname". The converted
- * path is returned in "bufp".
- *
- * Some of the directories specified in "fname" may not exist. This function
- * will shorten the existing directories at the beginning of the path and then
- * append the remaining non-existing path.
- *
- * fname - Pointer to the filename to shorten.  On return, contains the
- *	   pointer to the shortened pathname
- * bufp -  Pointer to an allocated buffer for the filename.
- * fnamelen - Length of the filename pointed to by fname
- *
- * Returns OK on success (or nothing done) and FAIL on failure (out of memory).
- */
-    static int
-shortpath_for_invalid_fname(
-    char_u	**fname,
-    char_u	**bufp,
-    int		*fnamelen)
-{
-    char_u	*short_fname, *save_fname, *pbuf_unused;
-    char_u	*endp, *save_endp;
-    char_u	ch;
-    int		old_len, len;
-    int		new_len, sfx_len;
-    int		retval = OK;
-
-    /* Make a copy */
-    old_len = *fnamelen;
-    save_fname = vim_strnsave(*fname, old_len);
-    pbuf_unused = NULL;
-    short_fname = NULL;
-
-    endp = save_fname + old_len - 1; /* Find the end of the copy */
-    save_endp = endp;
-
-    /*
-     * Try shortening the supplied path till it succeeds by removing one
-     * directory at a time from the tail of the path.
-     */
-    len = 0;
-    for (;;)
-    {
-	/* go back one path-separator */
-	while (endp > save_fname && !after_pathsep(save_fname, endp + 1))
-	    --endp;
-	if (endp <= save_fname)
-	    break;		/* processed the complete path */
-
-	/*
-	 * Replace the path separator with a NUL and try to shorten the
-	 * resulting path.
-	 */
-	ch = *endp;
-	*endp = 0;
-	short_fname = save_fname;
-	len = (int)STRLEN(short_fname) + 1;
-	if (get_short_pathname(&short_fname, &pbuf_unused, &len) == FAIL)
-	{
-	    retval = FAIL;
-	    goto theend;
-	}
-	*endp = ch;	/* preserve the string */
-
-	if (len > 0)
-	    break;	/* successfully shortened the path */
-
-	/* failed to shorten the path. Skip the path separator */
-	--endp;
-    }
-
-    if (len > 0)
-    {
-	/*
-	 * Succeeded in shortening the path. Now concatenate the shortened
-	 * path with the remaining path at the tail.
-	 */
-
-	/* Compute the length of the new path. */
-	sfx_len = (int)(save_endp - endp) + 1;
-	new_len = len + sfx_len;
-
-	*fnamelen = new_len;
-	vim_free(*bufp);
-	if (new_len > old_len)
-	{
-	    /* There is not enough space in the currently allocated string,
-	     * copy it to a buffer big enough. */
-	    *fname = *bufp = vim_strnsave(short_fname, new_len);
-	    if (*fname == NULL)
-	    {
-		retval = FAIL;
-		goto theend;
-	    }
-	}
-	else
-	{
-	    /* Transfer short_fname to the main buffer (it's big enough),
-	     * unless get_short_pathname() did its work in-place. */
-	    *fname = *bufp = save_fname;
-	    if (short_fname != save_fname)
-		vim_strncpy(save_fname, short_fname, len);
-	    save_fname = NULL;
-	}
-
-	/* concat the not-shortened part of the path */
-	vim_strncpy(*fname + len, endp, sfx_len);
-	(*fname)[new_len] = NUL;
-    }
-
-theend:
-    vim_free(pbuf_unused);
-    vim_free(save_fname);
-
-    return retval;
-}
-
-/*
- * Get a pathname for a partial path.
- * Returns OK for success, FAIL for failure.
- */
-    static int
-shortpath_for_partial(
-    char_u	**fnamep,
-    char_u	**bufp,
-    int		*fnamelen)
-{
-    int		sepcount, len, tflen;
-    char_u	*p;
-    char_u	*pbuf, *tfname;
-    int		hasTilde;
-
-    /* Count up the path separators from the RHS.. so we know which part
-     * of the path to return. */
-    sepcount = 0;
-    for (p = *fnamep; p < *fnamep + *fnamelen; MB_PTR_ADV(p))
-	if (vim_ispathsep(*p))
-	    ++sepcount;
-
-    /* Need full path first (use expand_env() to remove a "~/") */
-    hasTilde = (**fnamep == '~');
-    if (hasTilde)
-	pbuf = tfname = expand_env_save(*fnamep);
-    else
-	pbuf = tfname = FullName_save(*fnamep, FALSE);
-
-    len = tflen = (int)STRLEN(tfname);
-
-    if (get_short_pathname(&tfname, &pbuf, &len) == FAIL)
-	return FAIL;
-
-    if (len == 0)
-    {
-	/* Don't have a valid filename, so shorten the rest of the
-	 * path if we can. This CAN give us invalid 8.3 filenames, but
-	 * there's not a lot of point in guessing what it might be.
-	 */
-	len = tflen;
-	if (shortpath_for_invalid_fname(&tfname, &pbuf, &len) == FAIL)
-	    return FAIL;
-    }
-
-    /* Count the paths backward to find the beginning of the desired string. */
-    for (p = tfname + len - 1; p >= tfname; --p)
-    {
-	if (has_mbyte)
-	    p -= mb_head_off(tfname, p);
-	if (vim_ispathsep(*p))
-	{
-	    if (sepcount == 0 || (hasTilde && sepcount == 1))
-		break;
-	    else
-		sepcount --;
-	}
-    }
-    if (hasTilde)
-    {
-	--p;
-	if (p >= tfname)
-	    *p = '~';
-	else
-	    return FAIL;
-    }
-    else
-	++p;
-
-    /* Copy in the string - p indexes into tfname - allocated at pbuf */
-    vim_free(*bufp);
-    *fnamelen = (int)STRLEN(p);
-    *bufp = pbuf;
-    *fnamep = p;
-
-    return OK;
-}
-#endif // MSWIN
-
-/*
- * Adjust a filename, according to a string of modifiers.
- * *fnamep must be NUL terminated when called.  When returning, the length is
- * determined by *fnamelen.
- * Returns VALID_ flags or -1 for failure.
- * When there is an error, *fnamep is set to NULL.
- */
-    int
-modify_fname(
-    char_u	*src,		// string with modifiers
-    int		tilde_file,	// "~" is a file name, not $HOME
-    int		*usedlen,	// characters after src that are used
-    char_u	**fnamep,	// file name so far
-    char_u	**bufp,		// buffer for allocated file name or NULL
-    int		*fnamelen)	// length of fnamep
-{
-    int		valid = 0;
-    char_u	*tail;
-    char_u	*s, *p, *pbuf;
-    char_u	dirname[MAXPATHL];
-    int		c;
-    int		has_fullname = 0;
-#ifdef MSWIN
-    char_u	*fname_start = *fnamep;
-    int		has_shortname = 0;
-#endif
-
-repeat:
-    /* ":p" - full path/file_name */
-    if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p')
-    {
-	has_fullname = 1;
-
-	valid |= VALID_PATH;
-	*usedlen += 2;
-
-	/* Expand "~/path" for all systems and "~user/path" for Unix and VMS */
-	if ((*fnamep)[0] == '~'
-#if !defined(UNIX) && !(defined(VMS) && defined(USER_HOME))
-		&& ((*fnamep)[1] == '/'
-# ifdef BACKSLASH_IN_FILENAME
-		    || (*fnamep)[1] == '\\'
-# endif
-		    || (*fnamep)[1] == NUL)
-#endif
-		&& !(tilde_file && (*fnamep)[1] == NUL)
-	   )
-	{
-	    *fnamep = expand_env_save(*fnamep);
-	    vim_free(*bufp);	/* free any allocated file name */
-	    *bufp = *fnamep;
-	    if (*fnamep == NULL)
-		return -1;
-	}
-
-	/* When "/." or "/.." is used: force expansion to get rid of it. */
-	for (p = *fnamep; *p != NUL; MB_PTR_ADV(p))
-	{
-	    if (vim_ispathsep(*p)
-		    && p[1] == '.'
-		    && (p[2] == NUL
-			|| vim_ispathsep(p[2])
-			|| (p[2] == '.'
-			    && (p[3] == NUL || vim_ispathsep(p[3])))))
-		break;
-	}
-
-	/* FullName_save() is slow, don't use it when not needed. */
-	if (*p != NUL || !vim_isAbsName(*fnamep))
-	{
-	    *fnamep = FullName_save(*fnamep, *p != NUL);
-	    vim_free(*bufp);	/* free any allocated file name */
-	    *bufp = *fnamep;
-	    if (*fnamep == NULL)
-		return -1;
-	}
-
-#ifdef MSWIN
-# if _WIN32_WINNT >= 0x0500
-	if (vim_strchr(*fnamep, '~') != NULL)
-	{
-	    // Expand 8.3 filename to full path.  Needed to make sure the same
-	    // file does not have two different names.
-	    // Note: problem does not occur if _WIN32_WINNT < 0x0500.
-	    WCHAR *wfname = enc_to_utf16(*fnamep, NULL);
-	    WCHAR buf[_MAX_PATH];
-
-	    if (wfname != NULL)
-	    {
-		if (GetLongPathNameW(wfname, buf, _MAX_PATH))
-		{
-		    char_u *p = utf16_to_enc(buf, NULL);
-
-		    if (p != NULL)
-		    {
-			vim_free(*bufp);    // free any allocated file name
-			*bufp = *fnamep = p;
-		    }
-		}
-		vim_free(wfname);
-	    }
-	}
-# endif
-#endif
-	/* Append a path separator to a directory. */
-	if (mch_isdir(*fnamep))
-	{
-	    /* Make room for one or two extra characters. */
-	    *fnamep = vim_strnsave(*fnamep, (int)STRLEN(*fnamep) + 2);
-	    vim_free(*bufp);	/* free any allocated file name */
-	    *bufp = *fnamep;
-	    if (*fnamep == NULL)
-		return -1;
-	    add_pathsep(*fnamep);
-	}
-    }
-
-    /* ":." - path relative to the current directory */
-    /* ":~" - path relative to the home directory */
-    /* ":8" - shortname path - postponed till after */
-    while (src[*usedlen] == ':'
-		  && ((c = src[*usedlen + 1]) == '.' || c == '~' || c == '8'))
-    {
-	*usedlen += 2;
-	if (c == '8')
-	{
-#ifdef MSWIN
-	    has_shortname = 1; /* Postpone this. */
-#endif
-	    continue;
-	}
-	pbuf = NULL;
-	/* Need full path first (use expand_env() to remove a "~/") */
-	if (!has_fullname)
-	{
-	    if (c == '.' && **fnamep == '~')
-		p = pbuf = expand_env_save(*fnamep);
-	    else
-		p = pbuf = FullName_save(*fnamep, FALSE);
-	}
-	else
-	    p = *fnamep;
-
-	has_fullname = 0;
-
-	if (p != NULL)
-	{
-	    if (c == '.')
-	    {
-		mch_dirname(dirname, MAXPATHL);
-		s = shorten_fname(p, dirname);
-		if (s != NULL)
-		{
-		    *fnamep = s;
-		    if (pbuf != NULL)
-		    {
-			vim_free(*bufp);   /* free any allocated file name */
-			*bufp = pbuf;
-			pbuf = NULL;
-		    }
-		}
-	    }
-	    else
-	    {
-		home_replace(NULL, p, dirname, MAXPATHL, TRUE);
-		/* Only replace it when it starts with '~' */
-		if (*dirname == '~')
-		{
-		    s = vim_strsave(dirname);
-		    if (s != NULL)
-		    {
-			*fnamep = s;
-			vim_free(*bufp);
-			*bufp = s;
-		    }
-		}
-	    }
-	    vim_free(pbuf);
-	}
-    }
-
-    tail = gettail(*fnamep);
-    *fnamelen = (int)STRLEN(*fnamep);
-
-    /* ":h" - head, remove "/file_name", can be repeated  */
-    /* Don't remove the first "/" or "c:\" */
-    while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h')
-    {
-	valid |= VALID_HEAD;
-	*usedlen += 2;
-	s = get_past_head(*fnamep);
-	while (tail > s && after_pathsep(s, tail))
-	    MB_PTR_BACK(*fnamep, tail);
-	*fnamelen = (int)(tail - *fnamep);
-#ifdef VMS
-	if (*fnamelen > 0)
-	    *fnamelen += 1; /* the path separator is part of the path */
-#endif
-	if (*fnamelen == 0)
-	{
-	    /* Result is empty.  Turn it into "." to make ":cd %:h" work. */
-	    p = vim_strsave((char_u *)".");
-	    if (p == NULL)
-		return -1;
-	    vim_free(*bufp);
-	    *bufp = *fnamep = tail = p;
-	    *fnamelen = 1;
-	}
-	else
-	{
-	    while (tail > s && !after_pathsep(s, tail))
-		MB_PTR_BACK(*fnamep, tail);
-	}
-    }
-
-    /* ":8" - shortname  */
-    if (src[*usedlen] == ':' && src[*usedlen + 1] == '8')
-    {
-	*usedlen += 2;
-#ifdef MSWIN
-	has_shortname = 1;
-#endif
-    }
-
-#ifdef MSWIN
-    /*
-     * Handle ":8" after we have done 'heads' and before we do 'tails'.
-     */
-    if (has_shortname)
-    {
-	/* Copy the string if it is shortened by :h and when it wasn't copied
-	 * yet, because we are going to change it in place.  Avoids changing
-	 * the buffer name for "%:8". */
-	if (*fnamelen < (int)STRLEN(*fnamep) || *fnamep == fname_start)
-	{
-	    p = vim_strnsave(*fnamep, *fnamelen);
-	    if (p == NULL)
-		return -1;
-	    vim_free(*bufp);
-	    *bufp = *fnamep = p;
-	}
-
-	/* Split into two implementations - makes it easier.  First is where
-	 * there isn't a full name already, second is where there is. */
-	if (!has_fullname && !vim_isAbsName(*fnamep))
-	{
-	    if (shortpath_for_partial(fnamep, bufp, fnamelen) == FAIL)
-		return -1;
-	}
-	else
-	{
-	    int		l = *fnamelen;
-
-	    /* Simple case, already have the full-name.
-	     * Nearly always shorter, so try first time. */
-	    if (get_short_pathname(fnamep, bufp, &l) == FAIL)
-		return -1;
-
-	    if (l == 0)
-	    {
-		/* Couldn't find the filename, search the paths. */
-		l = *fnamelen;
-		if (shortpath_for_invalid_fname(fnamep, bufp, &l) == FAIL)
-		    return -1;
-	    }
-	    *fnamelen = l;
-	}
-    }
-#endif // MSWIN
-
-    /* ":t" - tail, just the basename */
-    if (src[*usedlen] == ':' && src[*usedlen + 1] == 't')
-    {
-	*usedlen += 2;
-	*fnamelen -= (int)(tail - *fnamep);
-	*fnamep = tail;
-    }
-
-    /* ":e" - extension, can be repeated */
-    /* ":r" - root, without extension, can be repeated */
-    while (src[*usedlen] == ':'
-	    && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r'))
-    {
-	/* find a '.' in the tail:
-	 * - for second :e: before the current fname
-	 * - otherwise: The last '.'
-	 */
-	if (src[*usedlen + 1] == 'e' && *fnamep > tail)
-	    s = *fnamep - 2;
-	else
-	    s = *fnamep + *fnamelen - 1;
-	for ( ; s > tail; --s)
-	    if (s[0] == '.')
-		break;
-	if (src[*usedlen + 1] == 'e')		/* :e */
-	{
-	    if (s > tail)
-	    {
-		*fnamelen += (int)(*fnamep - (s + 1));
-		*fnamep = s + 1;
-#ifdef VMS
-		/* cut version from the extension */
-		s = *fnamep + *fnamelen - 1;
-		for ( ; s > *fnamep; --s)
-		    if (s[0] == ';')
-			break;
-		if (s > *fnamep)
-		    *fnamelen = s - *fnamep;
-#endif
-	    }
-	    else if (*fnamep <= tail)
-		*fnamelen = 0;
-	}
-	else				/* :r */
-	{
-	    if (s > tail)	/* remove one extension */
-		*fnamelen = (int)(s - *fnamep);
-	}
-	*usedlen += 2;
-    }
-
-    /* ":s?pat?foo?" - substitute */
-    /* ":gs?pat?foo?" - global substitute */
-    if (src[*usedlen] == ':'
-	    && (src[*usedlen + 1] == 's'
-		|| (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's')))
-    {
-	char_u	    *str;
-	char_u	    *pat;
-	char_u	    *sub;
-	int	    sep;
-	char_u	    *flags;
-	int	    didit = FALSE;
-
-	flags = (char_u *)"";
-	s = src + *usedlen + 2;
-	if (src[*usedlen + 1] == 'g')
-	{
-	    flags = (char_u *)"g";
-	    ++s;
-	}
-
-	sep = *s++;
-	if (sep)
-	{
-	    /* find end of pattern */
-	    p = vim_strchr(s, sep);
-	    if (p != NULL)
-	    {
-		pat = vim_strnsave(s, (int)(p - s));
-		if (pat != NULL)
-		{
-		    s = p + 1;
-		    /* find end of substitution */
-		    p = vim_strchr(s, sep);
-		    if (p != NULL)
-		    {
-			sub = vim_strnsave(s, (int)(p - s));
-			str = vim_strnsave(*fnamep, *fnamelen);
-			if (sub != NULL && str != NULL)
-			{
-			    *usedlen = (int)(p + 1 - src);
-			    s = do_string_sub(str, pat, sub, NULL, flags);
-			    if (s != NULL)
-			    {
-				*fnamep = s;
-				*fnamelen = (int)STRLEN(s);
-				vim_free(*bufp);
-				*bufp = s;
-				didit = TRUE;
-			    }
-			}
-			vim_free(sub);
-			vim_free(str);
-		    }
-		    vim_free(pat);
-		}
-	    }
-	    /* after using ":s", repeat all the modifiers */
-	    if (didit)
-		goto repeat;
-	}
-    }
-
-    if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S')
-    {
-	/* vim_strsave_shellescape() needs a NUL terminated string. */
-	c = (*fnamep)[*fnamelen];
-	if (c != NUL)
-	    (*fnamep)[*fnamelen] = NUL;
-	p = vim_strsave_shellescape(*fnamep, FALSE, FALSE);
-	if (c != NUL)
-	    (*fnamep)[*fnamelen] = c;
-	if (p == NULL)
-	    return -1;
-	vim_free(*bufp);
-	*bufp = *fnamep = p;
-	*fnamelen = (int)STRLEN(p);
-	*usedlen += 2;
-    }
-
-    return valid;
-}
+#endif // FEAT_EVAL
 
 /*
  * Perform a substitution on "str" with pattern "pat" and substitute "sub".
@@ -7134,5 +6491,3 @@ do_string_sub(
 
     return ret;
 }
-
-#endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */